0xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca>
0xCB 00-1F CBM serial IEC bus in development:
<mailto:michael.klein@puffin.lb.shuttle.de>
+0xDD 00-3F ZFCP device driver see drivers/s390/scsi/
+ <mailto:aherrman@de.ibm.com>
*
* FCP adapter driver for IBM eServer zSeries
*
- * Copyright 2002 IBM Corporation
+ * (C) Copyright IBM Corp. 2002, 2004
+ *
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com>
- * Aron Zeh <arzeh@de.ibm.com>
- * Wolfgang Taphorn <taphorn@de.ibm.com>
+ * Aron Zeh
+ * Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
*/
/* 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 *********************************************/
#include <asm/cpcmd.h> /* Debugging only */
#include <asm/processor.h> /* Debugging only */
+#include <linux/miscdevice.h>
+#include <linux/major.h>
+
/* accumulated log level (module parameter) */
static u32 loglevel = ZFCP_LOG_LEVEL_DEFAULTS;
static char *device;
int zfcp_reboot_handler(struct notifier_block *, unsigned long, void *);
/* FCP related */
-static void zfcp_nameserver_request_handler(struct zfcp_fsf_req *);
+static void zfcp_ns_gid_pn_handler(unsigned long);
/* miscellaneous */
#ifdef ZFCP_STAT_REQSIZES
static int zfcp_statistics_new(struct list_head *, u32);
#endif
+static inline int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);
+static inline int zfcp_sg_list_free(struct zfcp_sg_list *);
+static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, void *,
+ size_t);
+static inline int zfcp_sg_list_copy_to_user(void *, struct zfcp_sg_list *,
+ size_t);
+
+static int zfcp_cfdc_dev_ioctl(struct inode *, struct file *,
+ unsigned int, unsigned long);
+
+#define ZFCP_CFDC_IOC_MAGIC 0xDD
+#define ZFCP_CFDC_IOC \
+ _IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_sense_data)
+
+#ifdef CONFIG_S390_SUPPORT
+static struct ioctl_trans zfcp_ioctl_trans = {ZFCP_CFDC_IOC, (void*) sys_ioctl};
+#endif
+
+static struct file_operations zfcp_cfdc_fops = {
+ .ioctl = zfcp_cfdc_dev_ioctl
+};
+
+static struct miscdevice zfcp_cfdc_misc = {
+ .minor = ZFCP_CFDC_DEV_MINOR,
+ .name = ZFCP_CFDC_DEV_NAME,
+ .fops = &zfcp_cfdc_fops
+};
+
/*********************** KERNEL/MODULE PARAMETERS ***************************/
/* declare driver module init/cleanup functions */
if ((i % 32) == 31)
printk("\n");
}
- if ((i % 32) != 31)
+ if (((i-1) % 32) != 31)
printk("\n");
}
/****************************************************************/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER
-#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_OTHER
#ifdef ZFCP_STAT_REQSIZES
{
#ifdef ZFCP_DEBUG_COMMANDS
struct zfcp_adapter *adapter = fsf_req->adapter;
- Scsi_Cmnd *scsi_cmnd;
+ struct scsi_cmnd *scsi_cmnd;
int level = 3;
int i;
unsigned long flags;
sizeof (u32));
debug_event(adapter->cmd_dbf, level, &scsi_cmnd,
sizeof (unsigned long));
+ debug_event(adapter->cmd_dbf, level, &scsi_cmnd->cmnd,
+ min(ZFCP_CMD_DBF_LENGTH, (int)scsi_cmnd->cmd_len));
for (i = 0; i < add_length; i += ZFCP_CMD_DBF_LENGTH)
debug_event(adapter->cmd_dbf,
level,
#endif
}
+/* XXX additionally log unit if available */
+/* ---> introduce new parameter for unit, see 2.4 code */
void
-zfcp_cmd_dbf_event_scsi(const char *text, Scsi_Cmnd * scsi_cmnd)
+zfcp_cmd_dbf_event_scsi(const char *text, struct scsi_cmnd *scsi_cmnd)
{
#ifdef ZFCP_DEBUG_COMMANDS
struct zfcp_adapter *adapter;
debug_event(adapter->cmd_dbf, level, &scsi_cmnd->result, sizeof (u32));
debug_event(adapter->cmd_dbf, level, &scsi_cmnd,
sizeof (unsigned long));
+ debug_event(adapter->cmd_dbf, level, &scsi_cmnd->cmnd,
+ min(ZFCP_CMD_DBF_LENGTH, (int)scsi_cmnd->cmd_len));
if (likely(fsf_req)) {
debug_event(adapter->cmd_dbf, level, &fsf_req,
sizeof (unsigned long));
zfcp_init_device_configure(void)
{
int found = 0;
- unsigned long flags;
struct zfcp_adapter *adapter;
struct zfcp_port *port;
struct zfcp_unit *unit;
down(&zfcp_data.config_sema);
- read_lock_irqsave(&zfcp_data.config_lock, flags);
+ read_lock_irq(&zfcp_data.config_lock);
list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list)
if (strcmp(zfcp_data.init_busid,
zfcp_get_busid_by_adapter(adapter)) == 0) {
found = 1;
break;
}
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ read_unlock_irq(&zfcp_data.config_lock);
if (!found)
goto out_adapter;
port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0);
zfcp_statistics_init_all();
#endif
+#ifdef CONFIG_S390_SUPPORT
+ retval = register_ioctl32_conversion(zfcp_ioctl_trans.cmd,
+ zfcp_ioctl_trans.handler);
+ if (retval != 0) {
+ ZFCP_LOG_INFO("Cannot register a 32-bit support of "
+ "the IOC handler\n");
+ goto out_ioctl32;
+ }
+#endif
+ retval = misc_register(&zfcp_cfdc_misc);
+ if (retval != 0) {
+ ZFCP_LOG_INFO(
+ "Device file for the control file data channel "
+ "cannot be registered\n");
+ goto out_misc_register;
+ } else {
+ ZFCP_LOG_INFO(
+ "Device file for the control file data channel "
+ "has become MAJOR/MINOR numbers %d/%d\n",
+ ZFCP_CFDC_DEV_MAJOR, zfcp_cfdc_misc.minor);
+ }
+
/* Initialise proc semaphores */
sema_init(&zfcp_data.config_sema, 1);
out_ccw_register:
unregister_reboot_notifier(&zfcp_data.reboot_notifier);
+ misc_deregister(&zfcp_cfdc_misc);
+ out_misc_register:
+#ifdef CONFIG_S390_SUPPORT
+ unregister_ioctl32_conversion(zfcp_ioctl_trans.cmd);
+ out_ioctl32:
+#endif
#ifdef ZFCP_STAT_REQSIZES
zfcp_statistics_clear_all();
#endif
{
unregister_reboot_notifier(&zfcp_data.reboot_notifier);
zfcp_ccw_unregister();
+ misc_deregister(&zfcp_cfdc_misc);
+#ifdef CONFIG_S390_SUPPORT
+ unregister_ioctl32_conversion(zfcp_ioctl_trans.cmd);
+#endif
#ifdef ZFCP_STAT_REQSIZES
zfcp_statistics_clear_all();
#endif
return NOTIFY_DONE;
}
+
+/*
+ * function: zfcp_cfdc_dev_ioctl
+ *
+ * purpose: Handle control file upload/download transaction via IOCTL
+ * interface
+ *
+ * returns: 0 - Operation completed successfuly
+ * -ENOTTY - Unknown IOCTL command
+ * -EINVAL - Invalid sense data record
+ * -ENXIO - The FCP adapter is not available
+ * -EOPNOTSUPP - The FCP adapter does not have CFDC support
+ * -ENOMEM - Insufficient memory
+ * -EFAULT - User space memory I/O operation fault
+ * -EPERM - Cannot create or queue FSF request or create SBALs
+ */
+static int
+zfcp_cfdc_dev_ioctl(struct inode *inode, struct file *file,
+ unsigned int command, unsigned long buffer)
+{
+ struct zfcp_cfdc_sense_data sense_data, *sense_data_user;
+ struct zfcp_adapter *adapter = NULL;
+ struct zfcp_fsf_req *fsf_req = NULL;
+ struct zfcp_sg_list *sg_list = NULL;
+ u32 fsf_command, option;
+ char *bus_id = NULL;
+ int retval = 0;
+
+ ZFCP_LOG_NORMAL(
+ "Control file data channel transaction opened\n");
+
+ sg_list = kmalloc(sizeof(struct zfcp_sg_list), GFP_KERNEL);
+ if (sg_list == NULL) {
+ ZFCP_LOG_NORMAL(
+ "Not enough memory for the scatter-gather list\n");
+ retval = -ENOMEM;
+ goto out;
+ }
+ sg_list->count = 0;
+
+ if (command != ZFCP_CFDC_IOC) {
+ ZFCP_LOG_NORMAL(
+ "IOC request code 0x%x is not valid\n",
+ command);
+ retval = -ENOTTY;
+ goto out;
+ }
+
+ if ((sense_data_user = (struct zfcp_cfdc_sense_data*)buffer) == NULL) {
+ ZFCP_LOG_NORMAL(
+ "Sense data record is required\n");
+ retval = -EINVAL;
+ goto out;
+ }
+
+ retval = copy_from_user(&sense_data, sense_data_user,
+ sizeof(struct zfcp_cfdc_sense_data));
+ if (retval) {
+ ZFCP_LOG_NORMAL("Cannot copy sense data record from user space "
+ "memory\n");
+ retval = -EFAULT;
+ goto out;
+ }
+
+ if (sense_data.signature != ZFCP_CFDC_SIGNATURE) {
+ ZFCP_LOG_NORMAL(
+ "No valid sense data request signature 0x%08x found\n",
+ ZFCP_CFDC_SIGNATURE);
+ retval = -EINVAL;
+ goto out;
+ }
+
+ switch (sense_data.command) {
+
+ case ZFCP_CFDC_CMND_DOWNLOAD_NORMAL:
+ fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;
+ option = FSF_CFDC_OPTION_NORMAL_MODE;
+ break;
+
+ case ZFCP_CFDC_CMND_DOWNLOAD_FORCE:
+ fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;
+ option = FSF_CFDC_OPTION_FORCE;
+ break;
+
+ case ZFCP_CFDC_CMND_FULL_ACCESS:
+ fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;
+ option = FSF_CFDC_OPTION_FULL_ACCESS;
+ break;
+
+ case ZFCP_CFDC_CMND_RESTRICTED_ACCESS:
+ fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;
+ option = FSF_CFDC_OPTION_RESTRICTED_ACCESS;
+ break;
+
+ case ZFCP_CFDC_CMND_UPLOAD:
+ fsf_command = FSF_QTCB_UPLOAD_CONTROL_FILE;
+ option = 0;
+ break;
+
+ default:
+ ZFCP_LOG_NORMAL(
+ "Command code 0x%08x is not valid\n",
+ sense_data.command);
+ retval = -EINVAL;
+ goto out;
+ }
+
+ bus_id = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
+ if (bus_id == NULL) {
+ ZFCP_LOG_NORMAL("Out of memory!\n");
+ retval = -ENOMEM;
+ goto out;
+ }
+ snprintf(bus_id, BUS_ID_SIZE, "%d.%d.%04x",
+ (sense_data.devno >> 24),
+ (sense_data.devno >> 16) & 0xFF,
+ (sense_data.devno & 0xFFFF));
+
+ retval = -ENXIO;
+ read_lock_irq(&zfcp_data.config_lock);
+ list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) {
+ if (strncmp(bus_id, zfcp_get_busid_by_adapter(adapter),
+ BUS_ID_SIZE) == 0) {
+ zfcp_adapter_get(adapter);
+ retval = 0;
+ break;
+ }
+ }
+ read_unlock_irq(&zfcp_data.config_lock);
+
+ kfree(bus_id);
+
+ if (retval != 0) {
+ ZFCP_LOG_NORMAL("Specified adapter does not exist\n");
+ goto out;
+ }
+
+ if (sense_data.command & ZFCP_CFDC_WITH_CONTROL_FILE) {
+ retval = zfcp_sg_list_alloc(sg_list,
+ ZFCP_CFDC_MAX_CONTROL_FILE_SIZE);
+ if (retval) {
+ ZFCP_LOG_NORMAL("Not enough memory for the "
+ "scatter-gather list\n");
+ retval = -ENOMEM;
+ goto out;
+ }
+ }
+
+ if ((sense_data.command & ZFCP_CFDC_DOWNLOAD) &&
+ (sense_data.command & ZFCP_CFDC_WITH_CONTROL_FILE)) {
+ retval = zfcp_sg_list_copy_from_user(
+ sg_list, &sense_data_user->control_file,
+ ZFCP_CFDC_MAX_CONTROL_FILE_SIZE);
+ if (retval) {
+ ZFCP_LOG_NORMAL("Cannot copy control file from user "
+ "space memory\n");
+ retval = -EFAULT;
+ goto out;
+ }
+ }
+
+ retval = zfcp_fsf_control_file(
+ adapter, &fsf_req, fsf_command, option, sg_list);
+ if (retval == -EOPNOTSUPP) {
+ ZFCP_LOG_NORMAL(
+ "Specified adapter does not support control file\n");
+ goto out;
+ } else if (retval != 0) {
+ ZFCP_LOG_NORMAL(
+ "Cannot create or queue FSF request or create SBALs\n");
+ retval = -EPERM;
+ goto out;
+ }
+
+ wait_event(fsf_req->completion_wq,
+ fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
+
+ sense_data.fsf_status = fsf_req->qtcb->header.fsf_status;
+ memcpy(&sense_data.fsf_status_qual,
+ &fsf_req->qtcb->header.fsf_status_qual,
+ sizeof(union fsf_status_qual));
+ memcpy(&sense_data.payloads, &fsf_req->qtcb->bottom.support.els, 256);
+
+ retval = copy_to_user(sense_data_user, &sense_data,
+ sizeof(struct zfcp_cfdc_sense_data));
+ if (retval) {
+ ZFCP_LOG_NORMAL(
+ "Cannot copy sense data record to user space memory\n");
+ retval = -EFAULT;
+ goto out;
+ }
+
+ if (sense_data.command & ZFCP_CFDC_UPLOAD) {
+ retval = zfcp_sg_list_copy_to_user(
+ &sense_data_user->control_file, sg_list,
+ ZFCP_CFDC_MAX_CONTROL_FILE_SIZE);
+ if (retval) {
+ ZFCP_LOG_NORMAL("Cannot copy control file to user "
+ "space memory\n");
+ retval = -EFAULT;
+ goto out;
+ }
+ }
+
+ out:
+ if (fsf_req != NULL)
+ zfcp_fsf_req_cleanup(fsf_req);
+
+ if ((adapter != NULL) && (retval != -ENXIO))
+ zfcp_adapter_put(adapter);
+
+ if (sg_list != NULL) {
+ zfcp_sg_list_free(sg_list);
+ kfree(sg_list);
+ }
+
+ ZFCP_LOG_NORMAL(
+ "Control file data channel transaction closed\n");
+
+ return retval;
+}
+
+
+/*
+ * function: zfcp_sg_list_alloc
+ *
+ * purpose: Create a scatter-gather list of the specified size
+ *
+ * returns: 0 - Scatter gather list is created
+ * -ENOMEM - Insufficient memory (*list_ptr is then set to NULL)
+ */
+static inline int
+zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
+{
+ struct scatterlist *sg;
+ int i;
+ int retval = 0;
+
+ sg_list->count = size >> PAGE_SHIFT;
+ if (size & ~PAGE_MASK)
+ sg_list->count++;
+ sg_list->sg = kmalloc(sg_list->count * sizeof(struct scatterlist),
+ GFP_KERNEL);
+ if (sg_list->sg == NULL) {
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) {
+ sg->length = min(size, PAGE_SIZE);
+ sg->offset = 0;
+ sg->page = alloc_pages(GFP_KERNEL, 0);
+ if (sg->page == NULL) {
+ sg_list->count = i;
+ zfcp_sg_list_free(sg_list);
+ retval = -ENOMEM;
+ goto out;
+ }
+ size -= sg->length;
+ }
+
+ out:
+ return retval;
+}
+
+
+/*
+ * function: zfcp_sg_list_free
+ *
+ * purpose: Destroy a scatter-gather list and release memory
+ *
+ * returns: Always 0
+ */
+static inline int
+zfcp_sg_list_free(struct zfcp_sg_list *sg_list)
+{
+ struct scatterlist *sg;
+ int i;
+ int retval = 0;
+
+ BUG_ON((sg_list->sg == NULL) || (sg_list == NULL));
+
+ for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++)
+ __free_pages(sg->page, 0);
+
+ return retval;
+}
+
+
+/*
+ * function: zfcp_sg_list_copy_from_user
+ *
+ * purpose: Copy data from user space memory to the scatter-gather list
+ *
+ * returns: 0 - The data has been copied from user
+ * -EFAULT - Memory I/O operation fault
+ */
+static inline int
+zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, void *user_buffer,
+ size_t size)
+{
+ struct scatterlist *sg;
+ unsigned int length;
+ void *zfcp_buffer;
+ int retval = 0;
+
+ for (sg = sg_list->sg; size > 0; sg++) {
+ length = min((unsigned int)size, sg->length);
+ zfcp_buffer = (void*)
+ ((page_to_pfn(sg->page) << PAGE_SHIFT) + sg->offset);
+ if (copy_from_user(zfcp_buffer, user_buffer, length)) {
+ ZFCP_LOG_INFO("Memory error (copy_from_user)\n");
+ retval = -EFAULT;
+ goto out;
+ }
+ user_buffer += length;
+ size -= length;
+ }
+
+ out:
+ return retval;
+}
+
+
+/*
+ * function: zfcp_sg_list_copy_to_user
+ *
+ * purpose: Copy data from the scatter-gather list to user space memory
+ *
+ * returns: 0 - The data has been copied to user
+ * -EFAULT - Memory I/O operation fault
+ */
+static inline int
+zfcp_sg_list_copy_to_user(void *user_buffer, struct zfcp_sg_list *sg_list,
+ size_t size)
+{
+ struct scatterlist *sg;
+ unsigned int length;
+ void *zfcp_buffer;
+ int retval = 0;
+
+ for (sg = sg_list->sg; size > 0; sg++) {
+ length = min((unsigned int)size, sg->length);
+ zfcp_buffer = (void*)
+ ((page_to_pfn(sg->page) << PAGE_SHIFT) + sg->offset);
+ if (copy_to_user(user_buffer, zfcp_buffer, length)) {
+ ZFCP_LOG_INFO("Memory error (copy_to_user)\n");
+ retval = -EFAULT;
+ goto out;
+ }
+ user_buffer += length;
+ size -= length;
+ }
+
+ out:
+ return retval;
+}
+
+
#undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
/****************************************************************/
/****** Functions for configuration/set-up of structures ********/
/****************************************************************/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG
-#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_CONFIG
/**
* zfcp_get_unit_by_lun - find unit in unit list of port by fcp lun
static int
zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
{
- adapter->pool.erp_fsf = mempool_create(
- 1,
- zfcp_mempool_alloc,
- zfcp_mempool_free,
- (void *) ZFCP_QTCB_AND_REQ_SIZE);
- if (!adapter->pool.erp_fsf) {
- ZFCP_LOG_INFO
- ("error: FCP command buffer pool allocation failed\n");
+ adapter->pool.fsf_req_erp =
+ mempool_create(ZFCP_POOL_FSF_REQ_ERP_NR,
+ zfcp_mempool_alloc, zfcp_mempool_free, (void *)
+ sizeof(struct zfcp_fsf_req_pool_element));
+
+ if (NULL == adapter->pool.fsf_req_erp) {
+ ZFCP_LOG_INFO("error: pool allocation failed (fsf_req_erp)\n");
return -ENOMEM;
}
- adapter->pool.nameserver = mempool_create(
- 1,
- zfcp_mempool_alloc,
- zfcp_mempool_free,
- (void *) (2 * sizeof (struct fc_ct_iu)));
- if (!adapter->pool.nameserver) {
- ZFCP_LOG_INFO
- ("error: Nameserver buffer pool allocation failed\n");
+ adapter->pool.fsf_req_scsi =
+ mempool_create(ZFCP_POOL_FSF_REQ_SCSI_NR,
+ zfcp_mempool_alloc, zfcp_mempool_free, (void *)
+ sizeof(struct zfcp_fsf_req_pool_element));
+
+ if (NULL == adapter->pool.fsf_req_scsi) {
+ ZFCP_LOG_INFO("error: pool allocation failed (fsf_req_scsi)\n");
return -ENOMEM;
}
- adapter->pool.status_read_fsf = mempool_create(
- ZFCP_STATUS_READS_RECOM,
- zfcp_mempool_alloc,
- zfcp_mempool_free,
- (void *) sizeof (struct zfcp_fsf_req));
- if (!adapter->pool.status_read_fsf) {
- ZFCP_LOG_INFO
- ("error: Status read request pool allocation failed\n");
+ adapter->pool.fsf_req_abort =
+ mempool_create(ZFCP_POOL_FSF_REQ_ABORT_NR,
+ zfcp_mempool_alloc, zfcp_mempool_free, (void *)
+ sizeof(struct zfcp_fsf_req_pool_element));
+
+ if (NULL == adapter->pool.fsf_req_abort) {
+ ZFCP_LOG_INFO("error: pool allocation failed "
+ "(fsf_req_abort)\n");
return -ENOMEM;
}
- adapter->pool.status_read_buf = mempool_create(
- ZFCP_STATUS_READS_RECOM,
- zfcp_mempool_alloc,
- zfcp_mempool_free,
- (void *) sizeof (struct fsf_status_read_buffer));
- if (!adapter->pool.status_read_buf) {
- ZFCP_LOG_INFO
- ("error: Status read buffer pool allocation failed\n");
+ adapter->pool.fsf_req_status_read =
+ mempool_create(ZFCP_POOL_STATUS_READ_NR,
+ zfcp_mempool_alloc, zfcp_mempool_free,
+ (void *) sizeof(struct zfcp_fsf_req));
+
+ if (NULL == adapter->pool.fsf_req_status_read) {
+ ZFCP_LOG_INFO("error: pool allocation failed "
+ "(fsf_req_status_read\n");
return -ENOMEM;
}
- adapter->pool.fcp_command_fsf = mempool_create(
- 1,
- zfcp_mempool_alloc,
- zfcp_mempool_free,
- (void *)
- ZFCP_QTCB_AND_REQ_SIZE);
- if (!adapter->pool.fcp_command_fsf) {
- ZFCP_LOG_INFO
- ("error: FCP command buffer pool allocation failed\n");
+ adapter->pool.data_status_read =
+ mempool_create(ZFCP_POOL_STATUS_READ_NR,
+ zfcp_mempool_alloc, zfcp_mempool_free,
+ (void *) sizeof(struct fsf_status_read_buffer));
+
+ if (NULL == adapter->pool.data_status_read) {
+ ZFCP_LOG_INFO("error: pool allocation failed "
+ "(data_status_read)\n");
+ return -ENOMEM;
+ }
+
+ adapter->pool.data_gid_pn =
+ mempool_create(ZFCP_POOL_DATA_GID_PN_NR,
+ zfcp_mempool_alloc, zfcp_mempool_free, (void *)
+ sizeof(struct zfcp_gid_pn_data));
+
+ if (NULL == adapter->pool.data_gid_pn) {
+ ZFCP_LOG_INFO("error: pool allocation failed (data_gid_pn)\n");
return -ENOMEM;
}
- init_timer(&adapter->pool.fcp_command_fsf_timer);
- adapter->pool.fcp_command_fsf_timer.function =
- zfcp_erp_scsi_low_mem_buffer_timeout_handler;
- adapter->pool.fcp_command_fsf_timer.data = (unsigned long) adapter;
return 0;
}
-/* locks: must only be called with zfcp_data.config_sema taken */
+/**
+ * zfcp_free_low_mem_buffers - free memory pools of an adapter
+ * @adapter: pointer to zfcp_adapter for which memory pools should be freed
+ * locking: zfcp_data.config_sema must be held
+ */
static void
zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
{
- if (adapter->pool.status_read_fsf)
- mempool_destroy(adapter->pool.status_read_fsf);
- if (adapter->pool.status_read_buf)
- mempool_destroy(adapter->pool.status_read_buf);
- if (adapter->pool.nameserver)
- mempool_destroy(adapter->pool.nameserver);
- if (adapter->pool.erp_fsf)
- mempool_destroy(adapter->pool.erp_fsf);
- if (adapter->pool.fcp_command_fsf)
- mempool_destroy(adapter->pool.fcp_command_fsf);
+ if (adapter->pool.fsf_req_erp)
+ mempool_destroy(adapter->pool.fsf_req_erp);
+ if (adapter->pool.fsf_req_scsi)
+ mempool_destroy(adapter->pool.fsf_req_scsi);
+ if (adapter->pool.fsf_req_abort)
+ mempool_destroy(adapter->pool.fsf_req_abort);
+ if (adapter->pool.fsf_req_status_read)
+ mempool_destroy(adapter->pool.fsf_req_status_read);
+ if (adapter->pool.data_status_read)
+ mempool_destroy(adapter->pool.data_status_read);
+ if (adapter->pool.data_gid_pn)
+ mempool_destroy(adapter->pool.data_gid_pn);
}
/*
#ifdef ZFCP_DEBUG_REQUESTS
/* debug feature area which records fsf request sequence numbers */
- sprintf(dbf_name, ZFCP_REQ_DBF_NAME "0x%s",
+ sprintf(dbf_name, ZFCP_REQ_DBF_NAME "%s",
zfcp_get_busid_by_adapter(adapter));
adapter->req_dbf = debug_register(dbf_name,
ZFCP_REQ_DBF_INDEX,
debug_register_view(adapter->erp_dbf, &debug_hex_ascii_view);
debug_set_level(adapter->erp_dbf, ZFCP_ERP_DBF_LEVEL);
- retval = zfcp_erp_thread_setup(adapter);
- if (retval) {
- ZFCP_LOG_INFO("error: out of resources. "
- "error recovery thread for the adapter %s "
- "could not be started\n",
- zfcp_get_busid_by_adapter(adapter));
- goto thread_failed;
- }
-
/* put allocated adapter at list tail */
write_lock_irq(&zfcp_data.config_lock);
atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
goto out;
- thread_failed:
- if (qdio_free(adapter->ccw_device) != 0)
- ZFCP_LOG_NORMAL
- ("bug: could not free memory used by data transfer "
- "mechanism for adapter %s\n",
- zfcp_get_busid_by_adapter(adapter));
-
- debug_unregister(adapter->erp_dbf);
-
failed_erp_dbf:
#ifdef ZFCP_DEBUG_INCOMING_ELS
debug_unregister(adapter->in_els_dbf);
dev_set_drvdata(&ccw_device->dev, NULL);
failed_low_mem_buffers:
zfcp_free_low_mem_buffers(adapter);
- qdio_free(ccw_device);
+ if (qdio_free(ccw_device) != 0)
+ ZFCP_LOG_NORMAL
+ ("bug: could not free memory used by data transfer "
+ "mechanism for adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
qdio_allocate_failed:
zfcp_qdio_free_queues(adapter);
queues_alloc_failed:
"%i adapters still in list\n",
(unsigned long) adapter, zfcp_data.adapters);
- retval = zfcp_erp_thread_kill(adapter);
-
- retval |= qdio_free(adapter->ccw_device);
+ retval = qdio_free(adapter->ccw_device);
if (retval)
ZFCP_LOG_NORMAL
("bug: could not free memory used by data transfer "
}
#undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
/****************************************************************/
/******* Fibre Channel Standard related Functions **************/
/****************************************************************/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_FC
-#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_FC
void
zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
"0x%Lx.\n", port->wwpn);
debug_text_event(adapter->erp_dbf, 1,
"unsol_els_rscnk:");
- zfcp_erp_port_reopen(port, 0);
+ zfcp_test_link(port);
}
}
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
zfcp_fsf_incoming_els_rscn(adapter, status_buffer);
else
zfcp_fsf_incoming_els_unknown(adapter, status_buffer);
-}
-/*
- * function: zfcp_release_nameserver_buffers
- *
- * purpose:
- *
- * returns:
- */
-static void
-zfcp_release_nameserver_buffers(struct zfcp_fsf_req *fsf_req)
-{
- struct zfcp_adapter *adapter = fsf_req->adapter;
- void *buffer = fsf_req->data.send_generic.outbuf;
-
- /* FIXME: not sure about appeal of this new flag (martin) */
- if (fsf_req->status & ZFCP_STATUS_FSFREQ_POOLBUF)
- mempool_free(buffer, adapter->pool.nameserver);
- else
- kfree(buffer);
}
-/*
- * function: zfcp_get_nameserver_buffers
- *
- * purpose:
- *
- * returns:
- *
- * locks: fsf_request_list_lock is held when doing buffer pool
- * operations
+
+/**
+ * zfcp_gid_pn_buffers_alloc - allocate buffers for GID_PN nameserver request
+ * @gid_pn: pointer to return pointer to struct zfcp_gid_pn_data
+ * @pool: pointer to mempool_t if non-null memory pool is used for allocation
*/
static int
-zfcp_get_nameserver_buffers(struct zfcp_fsf_req *fsf_req)
+zfcp_gid_pn_buffers_alloc(struct zfcp_gid_pn_data **gid_pn, mempool_t *pool)
{
- struct zfcp_send_generic *data = &fsf_req->data.send_generic;
- struct zfcp_adapter *adapter = fsf_req->adapter;
- int retval = 0;
+ struct zfcp_gid_pn_data *data;
- data->outbuf = kmalloc(2 * sizeof (struct fc_ct_iu), GFP_ATOMIC);
- if (data->outbuf) {
- memset(data->outbuf, 0, 2 * sizeof (struct fc_ct_iu));
+ if (pool != NULL) {
+ data = mempool_alloc(pool, GFP_ATOMIC);
+ if (likely(data != NULL)) {
+ data->ct.pool = pool;
+ }
} else {
- ZFCP_LOG_DEBUG("Out of memory. Could not allocate at "
- "least one of the buffers "
- "required for a name-server request on the"
- "adapter %s directly.. trying emergency pool\n",
- zfcp_get_busid_by_adapter(adapter));
- data->outbuf =
- mempool_alloc(adapter->pool.nameserver, GFP_ATOMIC);
- if (!data->outbuf) {
- ZFCP_LOG_DEBUG
- ("Out of memory. Could not get emergency "
- "buffer required for a name-server request "
- "on the adapter %s. All buffers are in "
- "use.\n",
- zfcp_get_busid_by_adapter(adapter));
- retval = -ENOMEM;
- goto out;
+ data = kmalloc(sizeof(struct zfcp_gid_pn_data), GFP_ATOMIC);
}
- memset(data->outbuf, 0, 2 * sizeof (struct fc_ct_iu));
- fsf_req->status |= ZFCP_STATUS_FSFREQ_POOLBUF;
+
+ if (NULL == data){
+ ZFCP_LOG_DEBUG("Out of memory.\n");
+ return -ENOMEM;
}
- data->outbuf_length = sizeof (struct fc_ct_iu);
- data->inbuf_length = sizeof (struct fc_ct_iu);
- data->inbuf =
- (char *) ((unsigned long) data->outbuf + sizeof (struct fc_ct_iu));
- out:
- return retval;
+
+ memset(data, 0, sizeof(*data));
+ data->ct.req = &data->req;
+ data->ct.resp = &data->resp;
+ data->ct.req_count = data->ct.resp_count = 1;
+ zfcp_address_to_sg(&data->ct_iu_req, &data->req);
+ zfcp_address_to_sg(&data->ct_iu_resp, &data->resp);
+ data->req.length = sizeof(struct ct_iu_gid_pn_req);
+ data->resp.length = sizeof(struct ct_iu_gid_pn_resp);
+
+ *gid_pn = data;
+ return 0;
}
-/*
- * function: zfcp_nameserver_request
- *
- * purpose:
- *
- * returns:
+/**
+ * zfcp_gid_pn_buffers_free - free buffers for GID_PN nameserver request
+ * @gid_pn: pointer to struct zfcp_gid_pn_data which has to be freed
*/
-int
-zfcp_nameserver_request(struct zfcp_erp_action *erp_action)
+static void
+zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn)
{
- int retval = 0;
- struct fc_ct_iu *fc_ct_iu;
- unsigned long lock_flags;
-
- /* setup new FSF request */
- retval = zfcp_fsf_req_create(erp_action->adapter,
- FSF_QTCB_SEND_GENERIC,
- &lock_flags,
- ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
- &(erp_action->fsf_req));
- if (retval < 0) {
- ZFCP_LOG_INFO("error: Out of resources. Could not create a "
- "nameserver registration request for "
- "adapter %s.\n",
- zfcp_get_busid_by_adapter(erp_action->adapter));
- goto failed_req;
- }
- retval = zfcp_get_nameserver_buffers(erp_action->fsf_req);
- if (retval < 0) {
- ZFCP_LOG_INFO("error: Out of memory. Could not allocate one of "
- "the buffers required for a nameserver request "
- "on adapter %s.\n",
- zfcp_get_busid_by_adapter(erp_action->adapter));
- goto failed_buffers;
+ if ((gid_pn->ct.pool != 0)) {
+ mempool_free(gid_pn, gid_pn->ct.pool);
+ } else {
+ kfree(gid_pn);
}
- /* setup name-server request in first page */
- fc_ct_iu =
- (struct fc_ct_iu *) erp_action->fsf_req->data.send_generic.outbuf;
- fc_ct_iu->revision = ZFCP_CT_REVISION;
- fc_ct_iu->gs_type = ZFCP_CT_DIRECTORY_SERVICE;
- fc_ct_iu->gs_subtype = ZFCP_CT_NAME_SERVER;
- fc_ct_iu->options = ZFCP_CT_SYNCHRONOUS;
- fc_ct_iu->cmd_rsp_code = ZFCP_CT_GID_PN;
- fc_ct_iu->max_res_size = ZFCP_CT_MAX_SIZE;
- fc_ct_iu->data.wwpn = erp_action->port->wwpn;
-
- erp_action->fsf_req->data.send_generic.handler =
- zfcp_nameserver_request_handler;
- erp_action->fsf_req->data.send_generic.handler_data =
- (unsigned long) erp_action->port;
- erp_action->fsf_req->data.send_generic.port =
- erp_action->adapter->nameserver_port;
- erp_action->fsf_req->erp_action = erp_action;
-
- /* send this one */
- retval = zfcp_fsf_send_generic(erp_action->fsf_req,
- ZFCP_NAMESERVER_TIMEOUT,
- &lock_flags,
- &erp_action->timer);
- if (retval) {
- ZFCP_LOG_INFO("error: Could not send a"
- "nameserver request command to adapter %s\n",
- zfcp_get_busid_by_adapter(erp_action->adapter));
- goto failed_send;
- }
+ return;
+}
+/**
+ * zfcp_ns_gid_pn_request - initiate GID_PN nameserver request
+ * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed
+ */
+int
+zfcp_ns_gid_pn_request(struct zfcp_erp_action *erp_action)
+{
+ int ret;
+ struct ct_iu_gid_pn_req *ct_iu_req;
+ struct zfcp_gid_pn_data *gid_pn;
+ struct zfcp_adapter *adapter = erp_action->adapter;
+
+ ret = zfcp_gid_pn_buffers_alloc(&gid_pn, adapter->pool.data_gid_pn);
+ if (ret < 0) {
+ ZFCP_LOG_INFO("error: Out of memory. Could not allocate "
+ "buffers for nameserver request GID_PN. "
+ "(adapter: %s)\n",
+ zfcp_get_busid_by_adapter(adapter));
goto out;
+ }
- failed_send:
- zfcp_release_nameserver_buffers(erp_action->fsf_req);
+ /* setup nameserver request */
+ ct_iu_req = zfcp_sg_to_address(gid_pn->ct.req);
+ ct_iu_req->header.revision = ZFCP_CT_REVISION;
+ ct_iu_req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE;
+ ct_iu_req->header.gs_subtype = ZFCP_CT_NAME_SERVER;
+ ct_iu_req->header.options = ZFCP_CT_SYNCHRONOUS;
+ ct_iu_req->header.cmd_rsp_code = ZFCP_CT_GID_PN;
+ ct_iu_req->header.max_res_size = ZFCP_CT_MAX_SIZE;
+ ct_iu_req->wwpn = erp_action->port->wwpn;
+
+ /* setup parameters for send generic command */
+ gid_pn->ct.port = adapter->nameserver_port;
+ gid_pn->ct.handler = zfcp_ns_gid_pn_handler;
+ gid_pn->ct.handler_data = (unsigned long) gid_pn;
+ gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT;
+ gid_pn->ct.timer = &erp_action->timer;
+ gid_pn->port = erp_action->port;
+
+ ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp,
+ erp_action);
+ if (ret) {
+ ZFCP_LOG_INFO("error: Could not send nameserver request GID_PN."
+ "(adapter %s)\n",
+ zfcp_get_busid_by_adapter(adapter));
- failed_buffers:
- zfcp_fsf_req_free(erp_action->fsf_req);
- erp_action->fsf_req = NULL;
+ zfcp_gid_pn_buffers_free(gid_pn);
+ }
- failed_req:
out:
- write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
- lock_flags);
- return retval;
+ return ret;
}
-/*
- * function: zfcp_nameserver_request_handler
- *
- * purpose:
- *
- * returns:
+/**
+ * zfcp_ns_gid_pn_handler - handler for GID_PN nameserver request
+ * @data: unsigned long, contains pointer to struct zfcp_gid_pn_data
*/
-static void
-zfcp_nameserver_request_handler(struct zfcp_fsf_req *fsf_req)
+static void zfcp_ns_gid_pn_handler(unsigned long data)
{
- struct fc_ct_iu *fc_ct_iu_resp =
- (struct fc_ct_iu *) (fsf_req->data.send_generic.inbuf);
- struct fc_ct_iu *fc_ct_iu_req =
- (struct fc_ct_iu *) (fsf_req->data.send_generic.outbuf);
- struct zfcp_port *port =
- (struct zfcp_port *) fsf_req->data.send_generic.handler_data;
-
- if (fc_ct_iu_resp->revision != ZFCP_CT_REVISION)
+ struct zfcp_port *port;
+ struct zfcp_send_ct *ct;
+ struct ct_iu_gid_pn_req *ct_iu_req;
+ struct ct_iu_gid_pn_resp *ct_iu_resp;
+ struct zfcp_gid_pn_data *gid_pn;
+
+
+ gid_pn = (struct zfcp_gid_pn_data *) data;
+ port = gid_pn->port;
+ ct = &gid_pn->ct;
+ ct_iu_req = zfcp_sg_to_address(ct->req);
+ ct_iu_resp = zfcp_sg_to_address(ct->resp);
+
+ if (ct_iu_resp->header.revision != ZFCP_CT_REVISION)
goto failed;
- if (fc_ct_iu_resp->gs_type != ZFCP_CT_DIRECTORY_SERVICE)
+ if (ct_iu_resp->header.gs_type != ZFCP_CT_DIRECTORY_SERVICE)
goto failed;
- if (fc_ct_iu_resp->gs_subtype != ZFCP_CT_NAME_SERVER)
+ if (ct_iu_resp->header.gs_subtype != ZFCP_CT_NAME_SERVER)
goto failed;
- if (fc_ct_iu_resp->options != ZFCP_CT_SYNCHRONOUS)
+ if (ct_iu_resp->header.options != ZFCP_CT_SYNCHRONOUS)
goto failed;
- if (fc_ct_iu_resp->cmd_rsp_code != ZFCP_CT_ACCEPT) {
+ if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) {
/* FIXME: do we need some specific erp entry points */
atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status);
goto failed;
}
/* paranoia */
- if (fc_ct_iu_req->data.wwpn != port->wwpn) {
- ZFCP_LOG_NORMAL("bug: Port WWPN returned by nameserver lookup "
- "does not correspond to "
- "the expected value on the adapter %s. "
- "(debug info 0x%Lx, 0x%Lx)\n",
- zfcp_get_busid_by_port(port),
- port->wwpn, fc_ct_iu_req->data.wwpn);
+ if (ct_iu_req->wwpn != port->wwpn) {
+ ZFCP_LOG_NORMAL(
+ "bug: Port WWPN returned by nameserver lookup "
+ "does not correspond to the expected value "
+ "(adapter: %s, debug info: 0x%016Lx, 0x%016Lx)\n",
+ zfcp_get_busid_by_port(port), port->wwpn,
+ ct_iu_req->wwpn);
goto failed;
}
/* looks like a valid d_id */
- port->d_id = ZFCP_DID_MASK & fc_ct_iu_resp->data.d_id;
+ port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK;
atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status);
ZFCP_LOG_DEBUG("busid %s: WWPN=0x%Lx ---> D_ID=0x%6.6x\n",
zfcp_get_busid_by_port(port),
port->wwpn, (unsigned int) port->d_id);
goto out;
- failed:
+failed:
ZFCP_LOG_NORMAL("warning: WWPN 0x%Lx not found by nameserver lookup "
- "using the adapter %s\n",
+ "(adapter: %s)\n",
port->wwpn, zfcp_get_busid_by_port(port));
ZFCP_LOG_DEBUG("CT IUs do not match:\n");
- ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
- (char *) fc_ct_iu_req, sizeof (struct fc_ct_iu));
- ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
- (char *) fc_ct_iu_resp, sizeof (struct fc_ct_iu));
+ ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_req,
+ sizeof(struct ct_iu_gid_pn_req));
+ ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_resp,
+ sizeof(struct ct_iu_gid_pn_resp));
out:
- zfcp_release_nameserver_buffers(fsf_req);
+ zfcp_gid_pn_buffers_free(gid_pn);
+ return;
}
#undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
*
* CCW driver related routines
*
- * Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
+ * (C) Copyright IBM Corp. 2003, 2004
+ *
* Authors:
* Martin Peschke <mpeschke@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#define ZFCP_CCW_C_REVISION "$Revision: 1.36 $"
+#define ZFCP_CCW_C_REVISION "$Revision: 1.48 $"
#include <linux/init.h>
#include <linux/module.h>
#include "zfcp_def.h"
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG
-#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_CONFIG
static int zfcp_ccw_probe(struct ccw_device *);
static void zfcp_ccw_remove(struct ccw_device *);
static int zfcp_ccw_set_online(struct ccw_device *);
static int zfcp_ccw_set_offline(struct ccw_device *);
+static int zfcp_ccw_notify(struct ccw_device *, int);
static struct ccw_device_id zfcp_ccw_device_id[] = {
{CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE,
ZFCP_CONTROL_UNIT_MODEL,
ZFCP_DEVICE_TYPE,
ZFCP_DEVICE_MODEL)},
+ {CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE,
+ ZFCP_CONTROL_UNIT_MODEL,
+ ZFCP_DEVICE_TYPE,
+ ZFCP_DEVICE_MODEL_PRIV)},
{},
};
.remove = zfcp_ccw_remove,
.set_online = zfcp_ccw_set_online,
.set_offline = zfcp_ccw_set_offline,
+ .notify = zfcp_ccw_notify,
};
MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
adapter = zfcp_adapter_enqueue(ccw_device);
if (!adapter)
retval = -EINVAL;
+ else
+ ZFCP_LOG_DEBUG("Probed adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
up(&zfcp_data.config_sema);
return retval;
}
down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev);
+ ZFCP_LOG_DEBUG("Removing adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
write_lock_irq(&zfcp_data.config_lock);
list_for_each_entry_safe(port, p, &adapter->port_list_head, list) {
list_for_each_entry_safe(unit, u, &port->unit_list_head, list) {
down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev);
+ retval = zfcp_erp_thread_setup(adapter);
+ if (retval) {
+ ZFCP_LOG_INFO("error: out of resources. "
+ "error recovery thread for adapter %s "
+ "could not be started\n",
+ zfcp_get_busid_by_adapter(adapter));
+ goto out;
+ }
+
retval = zfcp_adapter_scsi_register(adapter);
if (retval)
- goto out;
+ goto out_scsi_register;
zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING,
ZFCP_SET);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_erp_wait(adapter);
+ goto out;
+
+ out_scsi_register:
+ zfcp_erp_thread_kill(adapter);
out:
up(&zfcp_data.config_sema);
return retval;
zfcp_erp_adapter_shutdown(adapter, 0);
zfcp_erp_wait(adapter);
zfcp_adapter_scsi_unregister(adapter);
+ zfcp_erp_thread_kill(adapter);
up(&zfcp_data.config_sema);
return 0;
}
+/**
+ * zfcp_ccw_notify
+ * @ccw_device: pointer to belonging ccw device
+ * @event: indicates if adapter was detached or attached
+ *
+ * This function gets called by the common i/o layer if an adapter has gone
+ * or reappeared.
+ */
+static int
+zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
+{
+ struct zfcp_adapter *adapter;
+
+ down(&zfcp_data.config_sema);
+ adapter = dev_get_drvdata(&ccw_device->dev);
+ switch (event) {
+ case CIO_GONE:
+ ZFCP_LOG_NORMAL("Adapter %s: device gone.\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ case CIO_NO_PATH:
+ ZFCP_LOG_NORMAL("Adapter %s: no path.\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ case CIO_OPER:
+ ZFCP_LOG_NORMAL("Adapter %s: operational again.\n",
+ zfcp_get_busid_by_adapter(adapter));
+ zfcp_erp_modify_adapter_status(adapter,
+ ZFCP_STATUS_COMMON_RUNNING,
+ ZFCP_SET);
+ zfcp_erp_adapter_reopen(adapter,
+ ZFCP_STATUS_COMMON_ERP_FAILED);
+ break;
+ }
+ up(&zfcp_data.config_sema);
+ return 1;
+}
+
/**
* zfcp_ccw_register - ccw register function
*
}
#undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
*
* FCP adapter driver for IBM eServer zSeries
*
- * Copyright 2002 IBM Corporation
+ * (C) Copyright IBM Corp. 2002, 2004
+ *
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com>
- * Aron Zeh <arzeh@de.ibm.com>
- * Wolfgang Taphorn <taphorn@de.ibm.com>
+ * Aron Zeh
+ * Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
#define ZFCP_DEF_H
/* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_DEF_REVISION "$Revision: 1.48 $"
+#define ZFCP_DEF_REVISION "$Revision: 1.62 $"
/*************************** INCLUDES *****************************************/
#include <linux/blkdev.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
#include "../../scsi/scsi.h"
-#include "../../scsi/hosts.h"
#include "../../fc4/fc.h"
#include "zfcp_fsf.h" /* FSF SW Interface */
#include <asm/ccwdev.h>
#include <asm/qdio.h>
#include <asm/debug.h>
+#include <asm/ebcdic.h>
#include <linux/reboot.h>
+#include <linux/mempool.h>
+#include <linux/ioctl.h>
+#ifdef CONFIG_S390_SUPPORT
+#include <linux/ioctl32.h>
+#endif
/************************ DEBUG FLAGS *****************************************/
#define ZFCP_STAT_REQSIZES
#define ZFCP_STAT_QUEUES
+/********************* GENERAL DEFINES *********************************/
+
+/* zfcp version number, it consists of major, minor, and patch-level number */
+#define ZFCP_VERSION "4.0.0"
+
+static inline void *
+zfcp_sg_to_address(struct scatterlist *list)
+{
+ return (void *) (page_address(list->page) + list->offset);
+}
+
+static inline void
+zfcp_address_to_sg(void *address, struct scatterlist *list)
+{
+ list->page = virt_to_page(address);
+ list->offset = ((unsigned long) address) & (PAGE_SIZE - 1);
+}
+
/********************* SCSI SPECIFIC DEFINES *********************************/
/* 32 bit for SCSI ID and LUN as long as the SCSI stack uses this type */
#define ZFCP_ERP_SCSI_LOW_MEM_TIMEOUT (100*HZ)
#define ZFCP_SCSI_ER_TIMEOUT (100*HZ)
-#define ZFCP_SCSI_HOST_FLUSH_TIMEOUT (1*HZ)
/********************* CIO/QDIO SPECIFIC DEFINES *****************************/
#define ZFCP_CONTROL_UNIT_MODEL 0x03
#define ZFCP_DEVICE_TYPE 0x1732
#define ZFCP_DEVICE_MODEL 0x03
+#define ZFCP_DEVICE_MODEL_PRIV 0x04
/* allow as many chained SBALs as are supported by hardware */
#define ZFCP_MAX_SBALS_PER_REQ FSF_MAX_SBALS_PER_REQ
+#define ZFCP_MAX_SBALS_PER_CT_REQ FSF_MAX_SBALS_PER_REQ
+#define ZFCP_MAX_SBALS_PER_ELS_REQ FSF_MAX_SBALS_PER_ELS_REQ
/* DMQ bug workaround: don't use last SBALE */
#define ZFCP_MAX_SBALES_PER_SBAL (QDIO_MAX_ELEMENTS_PER_BUFFER - 1)
#define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 6
#define ZFCP_EXCHANGE_CONFIG_DATA_SLEEP 50
-#define ZFCP_QTCB_SIZE (sizeof(struct fsf_qtcb) + FSF_QTCB_LOG_SIZE)
-#define ZFCP_QTCB_AND_REQ_SIZE (sizeof(struct zfcp_fsf_req) + ZFCP_QTCB_SIZE)
-
/*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/
typedef unsigned long long wwn_t;
#define ZFCP_FC_SERVICE_CLASS_DEFAULT FSF_CLASS_3
/* timeout for name-server lookup (in seconds) */
-#define ZFCP_NAMESERVER_TIMEOUT 10
+#define ZFCP_NS_GID_PN_TIMEOUT 10
+#define ZFCP_NS_GA_NXT_TIMEOUT 120
/* largest SCSI command we can process */
/* FCP-2 (FCP_CMND IU) allows up to (255-3+16) */
wwn_t nport_wwpn;
} __attribute__((packed));
-struct fc_ct_iu {
- u8 revision; /* 0x01 */
- u8 in_id[3]; /* 0x00 */
- u8 gs_type; /* 0xFC Directory Service */
- u8 gs_subtype; /* 0x02 Name Server */
- u8 options; /* 0x10 synchronous/single exchange */
- u8 reserved0;
- u16 cmd_rsp_code; /* 0x0121 GID_PN */
- u16 max_res_size; /* <= (4096 - 16) / 4 */
- u8 reserved1;
+/*
+ * FC-FS stuff
+ */
+#define R_A_TOV 10 /* seconds */
+#define ZFCP_ELS_TIMEOUT (2 * R_A_TOV)
+
+#define ZFCP_LS_RJT 0x01
+#define ZFCP_LS_ACC 0x02
+#define ZFCP_LS_RTV 0x0E
+#define ZFCP_LS_RLS 0x0F
+#define ZFCP_LS_PDISC 0x50
+#define ZFCP_LS_ADISC 0x52
+#define ZFCP_LS_RSCN 0x61
+#define ZFCP_LS_RNID 0x78
+#define ZFCP_LS_RLIR 0x7A
+#define ZFCP_LS_RTV_E_D_TOV_FLAG 0x04000000
+
+/* LS_ACC Reason Codes */
+#define ZFCP_LS_RJT_INVALID_COMMAND_CODE 0x01
+#define ZFCP_LS_RJT_LOGICAL_ERROR 0x03
+#define ZFCP_LS_RJT_LOGICAL_BUSY 0x05
+#define ZFCP_LS_RJT_PROTOCOL_ERROR 0x07
+#define ZFCP_LS_RJT_UNABLE_TO_PERFORM 0x09
+#define ZFCP_LS_RJT_COMMAND_NOT_SUPPORTED 0x0B
+#define ZFCP_LS_RJT_VENDOR_UNIQUE_ERROR 0xFF
+
+struct zfcp_ls_rjt {
+ u8 code;
+ u8 field[3];
+ u8 reserved;
u8 reason_code;
- u8 reason_code_expl;
+ u8 reason_expl;
u8 vendor_unique;
- union {
+} __attribute__ ((packed));
+
+struct zfcp_ls_rtv {
+ u8 code;
+ u8 field[3];
+} __attribute__ ((packed));
+
+struct zfcp_ls_rtv_acc {
+ u8 code;
+ u8 field[3];
+ u32 r_a_tov;
+ u32 e_d_tov;
+ u32 qualifier;
+} __attribute__ ((packed));
+
+struct zfcp_ls_rls {
+ u8 code;
+ u8 field[3];
+ fc_id_t port_id;
+} __attribute__ ((packed));
+
+struct zfcp_ls_rls_acc {
+ u8 code;
+ u8 field[3];
+ u32 link_failure_count;
+ u32 loss_of_sync_count;
+ u32 loss_of_signal_count;
+ u32 prim_seq_prot_error;
+ u32 invalid_transmition_word;
+ u32 invalid_crc_count;
+} __attribute__ ((packed));
+
+struct zfcp_ls_pdisc {
+ u8 code;
+ u8 field[3];
+ u8 common_svc_parm[16];
wwn_t wwpn;
- fc_id_t d_id;
- } data;
+ wwn_t wwnn;
+ struct {
+ u8 class1[16];
+ u8 class2[16];
+ u8 class3[16];
+ } svc_parm;
+ u8 reserved[16];
+ u8 vendor_version[16];
} __attribute__ ((packed));
+struct zfcp_ls_pdisc_acc {
+ u8 code;
+ u8 field[3];
+ u8 common_svc_parm[16];
+ wwn_t wwpn;
+ wwn_t wwnn;
+ struct {
+ u8 class1[16];
+ u8 class2[16];
+ u8 class3[16];
+ } svc_parm;
+ u8 reserved[16];
+ u8 vendor_version[16];
+} __attribute__ ((packed));
+
+struct zfcp_ls_adisc {
+ u8 code;
+ u8 field[3];
+ fc_id_t hard_nport_id;
+ wwn_t wwpn;
+ wwn_t wwnn;
+ fc_id_t nport_id;
+} __attribute__ ((packed));
+
+struct zfcp_ls_adisc_acc {
+ u8 code;
+ u8 field[3];
+ fc_id_t hard_nport_id;
+ wwn_t wwpn;
+ wwn_t wwnn;
+ fc_id_t nport_id;
+} __attribute__ ((packed));
+
+struct zfcp_ls_rnid {
+ u8 code;
+ u8 field[3];
+ u8 node_id_format;
+ u8 reserved[3];
+} __attribute__((packed));
+
+/* common identification data */
+struct zfcp_ls_rnid_common_id {
+ u64 n_port_name;
+ u64 node_name;
+} __attribute__((packed));
+
+/* general topology specific identification data */
+struct zfcp_ls_rnid_general_topology_id {
+ u8 vendor_unique[16];
+ u32 associated_type;
+ u32 physical_port_number;
+ u32 nr_attached_nodes;
+ u8 node_management;
+ u8 ip_version;
+ u16 port_number;
+ u8 ip_address[16];
+ u8 reserved[2];
+ u16 vendor_specific;
+} __attribute__((packed));
+
+struct zfcp_ls_rnid_acc {
+ u8 code;
+ u8 field[3];
+ u8 node_id_format;
+ u8 common_id_length;
+ u8 reserved;
+ u8 specific_id_length;
+ struct zfcp_ls_rnid_common_id
+ common_id;
+ struct zfcp_ls_rnid_general_topology_id
+ specific_id;
+} __attribute__((packed));
+
+/*
+ * FC-GS-2 stuff
+ */
#define ZFCP_CT_REVISION 0x01
#define ZFCP_CT_DIRECTORY_SERVICE 0xFC
#define ZFCP_CT_NAME_SERVER 0x02
#define ZFCP_CT_SYNCHRONOUS 0x00
#define ZFCP_CT_GID_PN 0x0121
+#define ZFCP_CT_GA_NXT 0x0100
#define ZFCP_CT_MAX_SIZE 0x1020
#define ZFCP_CT_ACCEPT 0x8002
+/*
+ * FC-GS-4 stuff
+ */
+#define ZFCP_CT_TIMEOUT (3 * R_A_TOV)
+
+
/***************** S390 DEBUG FEATURE SPECIFIC DEFINES ***********************/
/* debug feature entries per adapter */
#define ZFCP_LOG_LEVEL_DEBUG 2
#define ZFCP_LOG_LEVEL_TRACE 3
-/* default log levels for different log areas */
-#define ZFCP_LOG_LEVEL_DEFAULT_OTHER ZFCP_LOG_LEVEL_INFO
-#define ZFCP_LOG_LEVEL_DEFAULT_SCSI ZFCP_LOG_LEVEL_INFO
-#define ZFCP_LOG_LEVEL_DEFAULT_FSF ZFCP_LOG_LEVEL_INFO
-#define ZFCP_LOG_LEVEL_DEFAULT_CONFIG ZFCP_LOG_LEVEL_INFO
-#define ZFCP_LOG_LEVEL_DEFAULT_CIO ZFCP_LOG_LEVEL_INFO
-#define ZFCP_LOG_LEVEL_DEFAULT_QDIO ZFCP_LOG_LEVEL_INFO
-#define ZFCP_LOG_LEVEL_DEFAULT_ERP ZFCP_LOG_LEVEL_INFO
-#define ZFCP_LOG_LEVEL_DEFAULT_FC ZFCP_LOG_LEVEL_INFO
-
/*
* this allows removal of logging code by the preprocessor
* (the most detailed log level still to be compiled in is specified,
*/
#define ZFCP_LOG_LEVEL_LIMIT ZFCP_LOG_LEVEL_TRACE
-/* positional "loglevel" nibble assignment */
-#define ZFCP_LOG_VALUE(zfcp_lognibble) \
+/* get "loglevel" nibble assignment */
+#define ZFCP_GET_LOG_VALUE(zfcp_lognibble) \
((atomic_read(&zfcp_data.loglevel) >> (zfcp_lognibble<<2)) & 0xF)
-#define ZFCP_LOG_VALUE_OTHER ZFCP_LOG_VALUE(ZFCP_LOG_AREA_OTHER)
-#define ZFCP_LOG_VALUE_SCSI ZFCP_LOG_VALUE(ZFCP_LOG_AREA_SCSI)
-#define ZFCP_LOG_VALUE_FSF ZFCP_LOG_VALUE(ZFCP_LOG_AREA_FSF)
-#define ZFCP_LOG_VALUE_CONFIG ZFCP_LOG_VALUE(ZFCP_LOG_AREA_CONFIG)
-#define ZFCP_LOG_VALUE_CIO ZFCP_LOG_VALUE(ZFCP_LOG_AREA_CIO)
-#define ZFCP_LOG_VALUE_QDIO ZFCP_LOG_VALUE(ZFCP_LOG_AREA_QDIO)
-#define ZFCP_LOG_VALUE_ERP ZFCP_LOG_VALUE(ZFCP_LOG_AREA_ERP)
-#define ZFCP_LOG_VALUE_FC ZFCP_LOG_VALUE(ZFCP_LOG_AREA_FC)
+/* set "loglevel" nibble */
+#define ZFCP_SET_LOG_NIBBLE(value, zfcp_lognibble) \
+ (value << (zfcp_lognibble << 2))
/* all log-level defaults are combined to generate initial log-level */
#define ZFCP_LOG_LEVEL_DEFAULTS \
- ((ZFCP_LOG_LEVEL_DEFAULT_OTHER << (ZFCP_LOG_AREA_OTHER<<2)) | \
- (ZFCP_LOG_LEVEL_DEFAULT_SCSI << (ZFCP_LOG_AREA_SCSI<<2)) | \
- (ZFCP_LOG_LEVEL_DEFAULT_FSF << (ZFCP_LOG_AREA_FSF<<2)) | \
- (ZFCP_LOG_LEVEL_DEFAULT_CONFIG << (ZFCP_LOG_AREA_CONFIG<<2)) | \
- (ZFCP_LOG_LEVEL_DEFAULT_CIO << (ZFCP_LOG_AREA_CIO<<2)) | \
- (ZFCP_LOG_LEVEL_DEFAULT_QDIO << (ZFCP_LOG_AREA_QDIO<<2)) | \
- (ZFCP_LOG_LEVEL_DEFAULT_ERP << (ZFCP_LOG_AREA_ERP<<2)) | \
- (ZFCP_LOG_LEVEL_DEFAULT_FC << (ZFCP_LOG_AREA_FC<<2)))
-
-/* the prefix placed at the beginning of each driver message */
-#define ZFCP_LOG_PREFIX ZFCP_NAME": "
-
-/* log area specific prefixes */
-#define ZFCP_LOG_AREA_PREFIX_OTHER ""
-#define ZFCP_LOG_AREA_PREFIX_SCSI "SCSI: "
-#define ZFCP_LOG_AREA_PREFIX_FSF "FSF: "
-#define ZFCP_LOG_AREA_PREFIX_CONFIG "config: "
-#define ZFCP_LOG_AREA_PREFIX_CIO "common I/O: "
-#define ZFCP_LOG_AREA_PREFIX_QDIO "QDIO: "
-#define ZFCP_LOG_AREA_PREFIX_ERP "ERP: "
-#define ZFCP_LOG_AREA_PREFIX_FC "FC: "
+ (ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_OTHER) | \
+ ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_SCSI) | \
+ ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_FSF) | \
+ ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_CONFIG) | \
+ ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_CIO) | \
+ ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_QDIO) | \
+ ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_ERP) | \
+ ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_FC))
/* check whether we have the right level for logging */
-#define ZFCP_LOG_CHECK(ll) (ZFCP_LOG_VALUE(ZFCP_LOG_AREA)) >= ll
+#define ZFCP_LOG_CHECK(level) \
+ ((ZFCP_GET_LOG_VALUE(ZFCP_LOG_AREA)) >= level)
-/* As we have two printks it is possible for them to be seperated by another
- * message. This holds true even for printks from within this module.
- * In any case there should only be a small readability hit, however.
- */
-#define _ZFCP_LOG(m...) \
- { \
- printk( "%s%s: ", \
- ZFCP_LOG_PREFIX ZFCP_LOG_AREA_PREFIX, \
- __FUNCTION__); \
- printk(m); \
- }
+/* logging routine for zfcp */
+#define _ZFCP_LOG(fmt, args...) \
+ printk(KERN_ERR ZFCP_NAME": %s(%d): " fmt, __FUNCTION__, \
+ __LINE__ , ##args);
-#define ZFCP_LOG(ll, m...) \
- if (ZFCP_LOG_CHECK(ll)) \
- _ZFCP_LOG(m)
+#define ZFCP_LOG(level, fmt, args...) \
+ if (ZFCP_LOG_CHECK(level)) \
+ _ZFCP_LOG(fmt , ##args)
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_NORMAL
-#define ZFCP_LOG_NORMAL(m...)
-#else /* ZFCP_LOG_LEVEL_LIMIT >= ZFCP_LOG_LEVEL_NORMAL */
-#define ZFCP_LOG_NORMAL(m...) ZFCP_LOG(ZFCP_LOG_LEVEL_NORMAL, m)
+# define ZFCP_LOG_NORMAL(fmt, args...)
+#else
+# define ZFCP_LOG_NORMAL(fmt, args...) \
+ if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_NORMAL)) \
+ printk(KERN_ERR ZFCP_NAME": " fmt , ##args);
#endif
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_INFO
-#define ZFCP_LOG_INFO(m...)
-#else /* ZFCP_LOG_LEVEL_LIMIT >= ZFCP_LOG_LEVEL_INFO */
-#define ZFCP_LOG_INFO(m...) ZFCP_LOG(ZFCP_LOG_LEVEL_INFO, m)
+# define ZFCP_LOG_INFO(fmt, args...)
+#else
+# define ZFCP_LOG_INFO(fmt, args...) \
+ if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_INFO)) \
+ printk(KERN_ERR ZFCP_NAME": " fmt , ##args);
#endif
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_DEBUG
-#define ZFCP_LOG_DEBUG(m...)
-#else /* ZFCP_LOG_LEVEL_LIMIT >= ZFCP_LOG_LEVEL_DEBUG */
-#define ZFCP_LOG_DEBUG(m...) ZFCP_LOG(ZFCP_LOG_LEVEL_DEBUG, m)
+# define ZFCP_LOG_DEBUG(fmt, args...)
+#else
+# define ZFCP_LOG_DEBUG(fmt, args...) \
+ ZFCP_LOG(ZFCP_LOG_LEVEL_DEBUG, fmt , ##args)
#endif
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_TRACE
-#define ZFCP_LOG_TRACE(m...)
-#else /* ZFCP_LOG_LEVEL_LIMIT >= ZFCP_LOG_LEVEL_TRACE */
-#define ZFCP_LOG_TRACE(m...) ZFCP_LOG(ZFCP_LOG_LEVEL_TRACE, m)
+# define ZFCP_LOG_TRACE(fmt, args...)
+#else
+# define ZFCP_LOG_TRACE(fmt, args...) \
+ ZFCP_LOG(ZFCP_LOG_LEVEL_TRACE, fmt , ##args)
#endif
-#ifdef ZFCP_PRINT_FLAGS
-extern u32 flags_dump;
-#define ZFCP_LOG_FLAGS(ll, m...) \
- if (ll<=flags_dump) \
- _ZFCP_LOG(m)
+#ifndef ZFCP_PRINT_FLAGS
+# define ZFCP_LOG_FLAGS(level, fmt, args...)
#else
-#define ZFCP_LOG_FLAGS(ll, m...)
+extern u32 flags_dump;
+# define ZFCP_LOG_FLAGS(level, fmt, args...) \
+ if (level <= flags_dump) \
+ _ZFCP_LOG(fmt , ##args)
#endif
/*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/
#define ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP 0x00000400
#define ZFCP_STATUS_FSFREQ_RETRY 0x00000800
#define ZFCP_STATUS_FSFREQ_DISMISSED 0x00001000
-#define ZFCP_STATUS_FSFREQ_POOLBUF 0x00002000
/*********************** ERROR RECOVERY PROCEDURE DEFINES ********************/
#define ZFCP_MAX_ERPS 3
-#define ZFCP_ERP_FSFREQ_TIMEOUT (100 * HZ)
+#define ZFCP_ERP_FSFREQ_TIMEOUT (30 * HZ)
#define ZFCP_ERP_MEMWAIT_TIMEOUT HZ
#define ZFCP_STATUS_ERP_TIMEDOUT 0x10000000
#define ZFCP_STATUS_ERP_CLOSE_ONLY 0x01000000
#define ZFCP_STATUS_ERP_DISMISSING 0x00100000
#define ZFCP_STATUS_ERP_DISMISSED 0x00200000
+#define ZFCP_STATUS_ERP_LOWMEM 0x00400000
#define ZFCP_ERP_STEP_UNINITIALIZED 0x00000000
#define ZFCP_ERP_STEP_FSF_XCONFIG 0x00000001
#define ZFCP_ERP_DISMISSED 0x4
#define ZFCP_ERP_NOMEM 0x5
-/************************* STRUCTURE DEFINITIONS *****************************/
+/******************** CFDC SPECIFIC STUFF *****************************/
+
+/* Firewall data channel sense data record */
+struct zfcp_cfdc_sense_data {
+ u32 signature; /* Request signature */
+ u32 devno; /* FCP adapter device number */
+ u32 command; /* Command code */
+ u32 fsf_status; /* FSF request status and status qualifier */
+ u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE];
+ u8 payloads[256]; /* Access conflicts list */
+ u8 control_file[0]; /* Access control table */
+};
+
+#define ZFCP_CFDC_SIGNATURE 0xCFDCACDF
+
+#define ZFCP_CFDC_CMND_DOWNLOAD_NORMAL 0x00010001
+#define ZFCP_CFDC_CMND_DOWNLOAD_FORCE 0x00010101
+#define ZFCP_CFDC_CMND_FULL_ACCESS 0x00000201
+#define ZFCP_CFDC_CMND_RESTRICTED_ACCESS 0x00000401
+#define ZFCP_CFDC_CMND_UPLOAD 0x00010002
+
+#define ZFCP_CFDC_DOWNLOAD 0x00000001
+#define ZFCP_CFDC_UPLOAD 0x00000002
+#define ZFCP_CFDC_WITH_CONTROL_FILE 0x00010000
+
+#define ZFCP_CFDC_DEV_NAME "zfcp_cfdc"
+#define ZFCP_CFDC_DEV_MAJOR MISC_MAJOR
+#define ZFCP_CFDC_DEV_MINOR MISC_DYNAMIC_MINOR
+
+#define ZFCP_CFDC_MAX_CONTROL_FILE_SIZE 127 * 1024
+
+static const char zfcp_act_subtable_type[5][8] = {
+ {"unknown"}, {"OS"}, {"WWPN"}, {"DID"}, {"LUN"}
+};
+
+
+/************************* STRUCTURE DEFINITIONS *****************************/
struct zfcp_fsf_req;
-typedef void zfcp_send_generic_handler_t(struct zfcp_fsf_req*);
+/* holds various memory pools of an adapter */
struct zfcp_adapter_mempool {
- mempool_t *status_read_fsf;
- mempool_t *status_read_buf;
- mempool_t *nameserver;
- mempool_t *erp_fsf;
- mempool_t *fcp_command_fsf;
- struct timer_list fcp_command_fsf_timer;
+ mempool_t *fsf_req_erp;
+ mempool_t *fsf_req_scsi;
+ mempool_t *fsf_req_abort;
+ mempool_t *fsf_req_status_read;
+ mempool_t *data_status_read;
+ mempool_t *data_gid_pn;
};
struct zfcp_exchange_config_data{
struct zfcp_send_fcp_command_task {
struct zfcp_fsf_req *fsf_req;
struct zfcp_unit *unit;
- Scsi_Cmnd *scsi_cmnd;
+ struct scsi_cmnd *scsi_cmnd;
unsigned long start_jiffies;
};
struct zfcp_unit *unit;
};
-struct zfcp_send_generic {
+/*
+ * header for CT_IU
+ */
+struct ct_hdr {
+ u8 revision; // 0x01
+ u8 in_id[3]; // 0x00
+ u8 gs_type; // 0xFC Directory Service
+ u8 gs_subtype; // 0x02 Name Server
+ u8 options; // 0x00 single bidirectional exchange
+ u8 reserved0;
+ u16 cmd_rsp_code; // 0x0121 GID_PN, or 0x0100 GA_NXT
+ u16 max_res_size; // <= (4096 - 16) / 4
+ u8 reserved1;
+ u8 reason_code;
+ u8 reason_code_expl;
+ u8 vendor_unique;
+} __attribute__ ((packed));
+
+/* nameserver request CT_IU -- for requests where
+ * a port name is required */
+struct ct_iu_gid_pn_req {
+ struct ct_hdr header;
+ wwn_t wwpn;
+} __attribute__ ((packed));
+
+/* nameserver request CT_IU -- for requests where
+ * a port identifier is required */
+struct ct_iu_ga_nxt_req {
+ struct ct_hdr header;
+ fc_id_t d_id;
+} __attribute__ ((packed));
+
+/* FS_ACC IU and data unit for GID_PN nameserver request */
+struct ct_iu_gid_pn_resp {
+ struct ct_hdr header;
+ fc_id_t d_id;
+} __attribute__ ((packed));
+
+/* FS_ACC IU and data unit for GA_NXT nameserver request */
+struct ct_iu_ga_nxt_resp {
+ struct ct_hdr header;
+ u8 port_type;
+ u8 port_id[3];
+ u64 port_wwn;
+ u8 port_symbolic_name_length;
+ u8 port_symbolic_name[255];
+ u64 node_wwn;
+ u8 node_symbolic_name_length;
+ u8 node_symbolic_name[255];
+ u64 initial_process_associator;
+ u8 node_ip[16];
+ u32 cos;
+ u8 fc4_types[32];
+ u8 port_ip[16];
+ u64 fabric_wwn;
+ u8 reserved;
+ u8 hard_address[3];
+} __attribute__ ((packed));
+
+typedef void (*zfcp_send_ct_handler_t)(unsigned long);
+
+/* used to pass parameters to zfcp_send_ct() */
+struct zfcp_send_ct {
+ struct zfcp_port *port;
+ struct scatterlist *req;
+ struct scatterlist *resp;
+ unsigned int req_count;
+ unsigned int resp_count;
+ zfcp_send_ct_handler_t handler;
+ unsigned long handler_data;
+ mempool_t *pool; /* mempool for ct not for fsf_req */
+ int timeout;
+ struct timer_list *timer;
+ struct completion *completion;
+ int status;
+};
+
+/* used for name server requests in error recovery */
+struct zfcp_gid_pn_data {
+ struct zfcp_send_ct ct;
+ struct scatterlist req;
+ struct scatterlist resp;
+ struct ct_iu_gid_pn_req ct_iu_req;
+ struct ct_iu_gid_pn_resp ct_iu_resp;
struct zfcp_port *port;
- char *outbuf;
- char *inbuf;
- int outbuf_length;
- int inbuf_length;
- zfcp_send_generic_handler_t *handler;
+};
+
+typedef int (*zfcp_send_els_handler_t)(unsigned long);
+
+/* used to pass parameters to zfcp_send_els() */
+/* ToDo merge send_ct() and send_els() and corresponding structs */
+struct zfcp_send_els {
+ struct zfcp_port *port;
+ struct scatterlist *req;
+ struct scatterlist *resp;
+ unsigned int req_count;
+ unsigned int resp_count;
+ zfcp_send_els_handler_t handler;
unsigned long handler_data;
+ struct completion *completion;
+ int ls_code;
+ int status;
};
struct zfcp_status_read {
struct fsf_status_read_buffer *buffer;
};
+struct zfcp_fsf_done {
+ struct completion *complete;
+ int status;
+};
+
/* request specific data */
union zfcp_req_data {
struct zfcp_exchange_config_data exchange_config_data;
struct zfcp_send_fcp_command_task_management
send_fcp_command_task_management;
struct zfcp_abort_fcp_command abort_fcp_command;
- struct zfcp_send_generic send_generic;
+ struct zfcp_send_ct *send_ct;
+ struct zfcp_send_els *send_els;
struct zfcp_status_read status_read;
};
u32 fc_link_speed; /* FC interface speed */
u32 hydra_version; /* Hydra version */
u32 fsf_lic_version;
+ u32 supported_features;/* of FCP channel */
+ u32 hardware_version; /* of FCP channel */
+ u8 serial_number[32]; /* of hardware */
struct Scsi_Host *scsi_host; /* Pointer to mid-layer */
unsigned char name[9];
wait_queue_head_t erp_done_wqh;
struct zfcp_erp_action erp_action; /* pending error recovery */
atomic_t erp_counter;
+ u32 erp_total_count; /* total nr of enqueued erp
+ actions */
+ u32 erp_low_mem_count; /* nr of erp actions waiting
+ for memory */
struct zfcp_port *nameserver_port; /* adapter's nameserver */
debug_info_t *erp_dbf; /* S/390 debug features */
debug_info_t *abort_dbf;
scsi_lun_t scsi_lun; /* own SCSI LUN */
fcp_lun_t fcp_lun; /* own FCP_LUN */
u32 handle; /* handle assigned by FSF */
- Scsi_Device *device; /* scsi device struct pointer */
+ struct scsi_device *device; /* scsi device struct pointer */
struct zfcp_erp_action erp_action; /* pending error recovery */
atomic_t erp_counter;
struct device sysfs_device; /* sysfs device */
u32 specific_magic; /* structure specific magic */
struct list_head list; /* list of FSF requests */
struct zfcp_adapter *adapter; /* adapter request belongs to */
- u8 sbal_count; /* # of SBALs in FSF request */
- u8 sbal_index; /* position of 1st SBAL */
+ u8 sbal_number; /* nr of SBALs free for use */
+ u8 sbal_first; /* first SBAL for this request */
+ u8 sbal_last; /* last possible SBAL for
+ this reuest */
+ u8 sbal_curr; /* current SBAL during creation
+ of request */
+ u8 sbale_curr; /* current SBALE during creation
+ of request */
wait_queue_head_t completion_wq; /* can be used by a routine
to wait for completion */
volatile u32 status; /* status of this request */
union zfcp_req_data data; /* Info fields of request */
struct zfcp_erp_action *erp_action; /* used if this request is
issued on behalf of erp */
+ mempool_t *pool; /* used if request was alloacted
+ from emergency pool */
};
typedef void zfcp_fsf_req_handler_t(struct zfcp_fsf_req*);
/* driver data */
struct zfcp_data {
- Scsi_Host_Template scsi_host_template;
+ struct scsi_host_template scsi_host_template;
atomic_t status; /* Module status flags */
struct list_head adapter_list_head; /* head of adapter list */
struct list_head adapter_remove_lh; /* head of adapters to be
struct list_head status_read_send_head;
struct semaphore status_read_sema;
wait_queue_head_t status_read_thread_wqh;
- u16 adapters; /* # of adapters in list */
+ u32 adapters; /* # of adapters in list */
rwlock_t config_lock; /* serialises changes
to adapter/port/unit
lists */
};
#endif
+struct zfcp_sg_list {
+ struct scatterlist *sg;
+ unsigned int count;
+};
+
+/* number of elements for various memory pools */
+#define ZFCP_POOL_FSF_REQ_ERP_NR 1
+#define ZFCP_POOL_FSF_REQ_SCSI_NR 1
+#define ZFCP_POOL_FSF_REQ_ABORT_NR 1
+#define ZFCP_POOL_STATUS_READ_NR ZFCP_STATUS_READS_RECOM
+#define ZFCP_POOL_DATA_GID_PN_NR 1
+
+/* struct used by memory pools for fsf_requests */
+struct zfcp_fsf_req_pool_element {
+ struct zfcp_fsf_req fsf_req;
+ struct fsf_qtcb qtcb;
+};
+
/********************** ZFCP SPECIFIC DEFINES ********************************/
#define ZFCP_FSFREQ_CLEANUP_TIMEOUT HZ/10
#define ZFCP_KNOWN 0x00000001
#define ZFCP_REQ_AUTO_CLEANUP 0x00000002
#define ZFCP_WAIT_FOR_SBAL 0x00000004
+#define ZFCP_REQ_NO_QTCB 0x00000008
#define ZFCP_SET 0x00000100
#define ZFCP_CLEAR 0x00000200
*
* FCP adapter driver for IBM eServer zSeries
*
- * Copyright 2002 IBM Corporation
+ * (C) Copyright IBM Corp. 2002, 2004
+ *
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com>
- * Aron Zeh <arzeh@de.ibm.com>
- * Wolfgang Taphorn <taphorn@de.ibm.com>
+ * Aron Zeh
+ * Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
*/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP
-#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_ERP
+
/* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_ERP_REVISION "$Revision: 1.39 $"
+#define ZFCP_ERP_REVISION "$Revision: 1.44 $"
#include "zfcp_ext.h"
+static int zfcp_els(struct zfcp_port *, u8);
+static int zfcp_els_handler(unsigned long);
+
static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *, int);
static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *, int);
static int zfcp_erp_port_reopen_internal(struct zfcp_port *, int);
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:
*
"a_ca_disreq");
fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
}
+ if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
+ ZFCP_LOG_NORMAL
+ ("error: Error Recovery Procedure "
+ "step timed out. The action flag "
+ "is 0x%x. The FSF request "
+ "is at 0x%lx\n",
+ erp_action->action,
+ (unsigned long)
+ erp_action->fsf_req);
+ }
/*
* If fsf_req is neither dismissed nor completed
- * then keep it running asynchronously and don't mess with
- * the association of erp_action and fsf_req.
+ * then keep it running asynchronously and don't mess
+ * with the association of erp_action and fsf_req.
*/
if (fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED |
ZFCP_STATUS_FSFREQ_DISMISSED)) {
- /* forget about association between fsf_req and erp_action */
+ /* forget about association between fsf_req
+ and erp_action */
fsf_req->erp_action = NULL;
erp_action->fsf_req = NULL;
- /* some special things for time out conditions */
- if (erp_action-> status & ZFCP_STATUS_ERP_TIMEDOUT) {
- ZFCP_LOG_NORMAL
- ("error: Error Recovery Procedure step timed out. "
- "The action flag is 0x%x. The FSF request "
- "is at 0x%lx\n", erp_action->action,
- (unsigned long) erp_action->fsf_req);
- /* fight for low memory buffer, if required */
- if (fsf_req->
- status & ZFCP_STATUS_FSFREQ_POOL) {
- debug_text_event(adapter->erp_dbf, 3,
- "a_ca_lowmem");
- ZFCP_LOG_NORMAL
- ("error: The error recovery action using the "
- "low memory pool timed out. Restarting IO on "
- "the adapter %s to free it.\n",
- zfcp_get_busid_by_adapter
- (adapter));
- zfcp_erp_adapter_reopen_internal(adapter, 0);
- }
- }
}
} else {
debug_text_event(adapter->erp_dbf, 3, "a_ca_gonereq");
goto unlock;
case ZFCP_ERP_NOMEM:
/* no memory to continue immediately, let it sleep */
+ if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) {
+ ++adapter->erp_low_mem_count;
+ erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
+ }
+ /* This condition is true if there is no memory available
+ for any erp_action on this adapter. This implies that there
+ are no elements in the memory pool(s) left for erp_actions.
+ This might happen if an erp_action that used a memory pool
+ element was timed out.
+ */
+ if (adapter->erp_total_count == adapter->erp_low_mem_count) {
+ debug_text_event(adapter->erp_dbf, 3, "a_st_lowmem");
+ ZFCP_LOG_NORMAL
+ ("error: Out of memory. No mempool elements "
+ "available. Restarting IO on the adapter %s "
+ "to free mempool.\n",
+ zfcp_get_busid_by_adapter(adapter));
+ zfcp_erp_adapter_reopen_internal(adapter, 0);
+ } else {
debug_text_event(adapter->erp_dbf, 2, "a_st_memw");
retval = zfcp_erp_strategy_memwait(erp_action);
- /* fall through, waiting for memory means action continues */
+ }
+ goto unlock;
case ZFCP_ERP_CONTINUES:
/* leave since this action runs asynchronously */
debug_text_event(adapter->erp_dbf, 6, "a_st_cont");
+ if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
+ --adapter->erp_low_mem_count;
+ erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
+ }
goto unlock;
}
/* ok, finished action (whatever its result is) */
debug_event(unit->port->adapter->erp_dbf, 5, &unit->fcp_lun,
sizeof (fcp_lun_t));
- if (result == ZFCP_ERP_SUCCEEDED) {
+ switch (result) {
+ case ZFCP_ERP_SUCCEEDED :
atomic_set(&unit->erp_counter, 0);
zfcp_erp_unit_unblock(unit);
- } else {
- /* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */
+ break;
+ case ZFCP_ERP_FAILED :
atomic_inc(&unit->erp_counter);
- if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) {
+ if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS)
zfcp_erp_unit_failed(unit);
- result = ZFCP_ERP_EXIT;
- }
+ break;
+ case ZFCP_ERP_EXIT :
+ /* nothing */
+ break;
+ }
+
+ if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)) {
+ zfcp_erp_unit_block(unit, 0); /* for ZFCP_ERP_SUCCEEDED */
+ result = ZFCP_ERP_EXIT;
}
return result;
debug_text_event(port->adapter->erp_dbf, 5, "p_stct");
debug_event(port->adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t));
- if (result == ZFCP_ERP_SUCCEEDED) {
+ switch (result) {
+ case ZFCP_ERP_SUCCEEDED :
atomic_set(&port->erp_counter, 0);
zfcp_erp_port_unblock(port);
- } else {
- /* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */
+ break;
+ case ZFCP_ERP_FAILED :
atomic_inc(&port->erp_counter);
- if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) {
+ if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS)
+ break;
+ case ZFCP_ERP_EXIT :
+ /* nothing */
+ break;
+ }
+
+ if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) {
+ zfcp_erp_port_block(port, 0); /* for ZFCP_ERP_SUCCEEDED */
+ result = ZFCP_ERP_EXIT;
zfcp_erp_port_failed(port);
- result = ZFCP_ERP_EXIT;
- }
}
return result;
{
debug_text_event(adapter->erp_dbf, 5, "a_stct");
- if (result == ZFCP_ERP_SUCCEEDED) {
+ switch (result) {
+ case ZFCP_ERP_SUCCEEDED :
atomic_set(&adapter->erp_counter, 0);
zfcp_erp_adapter_unblock(adapter);
- } else {
- /* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */
+ break;
+ case ZFCP_ERP_FAILED :
atomic_inc(&adapter->erp_counter);
- if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) {
+ if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS)
zfcp_erp_adapter_failed(adapter);
- result = ZFCP_ERP_EXIT;
- }
+ break;
+ case ZFCP_ERP_EXIT :
+ /* nothing */
+ break;
+ }
+
+ if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) {
+ zfcp_erp_adapter_block(adapter, 0); /* for ZFCP_ERP_SUCCEEDED */
+ result = ZFCP_ERP_EXIT;
}
return result;
int
zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
{
- int retval = 0;
- struct zfcp_adapter *adapter = erp_action->adapter;
+ int retval;
int i;
- volatile struct qdio_buffer_element *buffere;
+ volatile struct qdio_buffer_element *sbale;
+ struct zfcp_adapter *adapter = erp_action->adapter;
int retval_cleanup = 0;
if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) {
* put buffers into response queue,
*/
for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
- buffere = &(adapter->response_queue.buffer[i]->element[0]);
- buffere->length = 0;
- buffere->flags = SBAL_FLAGS_LAST_ENTRY;
- buffere->addr = 0;
+ sbale = &(adapter->response_queue.buffer[i]->element[0]);
+ sbale->length = 0;
+ sbale->flags = SBAL_FLAGS_LAST_ENTRY;
+ sbale->addr = 0;
}
ZFCP_LOG_TRACE("Calling do QDIO busid=%s, flags=0x%x, queue_no=%i, "
if (atomic_test_mask((ZFCP_STATUS_COMMON_OPEN |
ZFCP_STATUS_PORT_DID_DID),
&port->status)) {
- ZFCP_LOG_DEBUG("port wwpn=0x%Lx is open ", port->wwpn);
+ ZFCP_LOG_DEBUG("port wwpn=0x%Lx is open\n", port->wwpn);
retval = ZFCP_ERP_SUCCEEDED;
} else {
ZFCP_LOG_DEBUG("failed to open port wwpn=0x%Lx\n",
struct zfcp_port *port = erp_action->port;
zfcp_erp_timeout_init(erp_action);
- retval = zfcp_nameserver_request(erp_action);
+ retval = zfcp_ns_gid_pn_request(erp_action);
if (retval == -ENOMEM) {
debug_text_event(adapter->erp_dbf, 5, "p_pstn_nomem");
debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t));
* efficient.
*/
+ if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP,
+ &adapter->status))
+ goto out;
+
debug_event(adapter->erp_dbf, 4, &action, sizeof (int));
/* check whether we really need this */
switch (action) {
erp_action->action = action;
erp_action->status = status;
+ ++adapter->erp_total_count;
+
/* finally put it into 'ready' queue and kick erp thread */
list_add(&erp_action->list, &adapter->erp_ready_head);
up(&adapter->erp_ready_sem);
int retval = 0;
struct zfcp_adapter *adapter = erp_action->adapter;
+ --adapter->erp_total_count;
+ if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
+ --adapter->erp_low_mem_count;
+ erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
+ }
+
debug_text_event(adapter->erp_dbf, 4, "a_actdeq");
debug_event(adapter->erp_dbf, 4, &erp_action->action, sizeof (int));
list_del(&erp_action->list);
}
#undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
*
* FCP adapter driver for IBM eServer zSeries
*
- * Copyright 2002 IBM Corporation
+ * (C) Copyright IBM Corp. 2002, 2004
+ *
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com>
- * Aron Zeh <arzeh@de.ibm.com>
- * Wolfgang Taphorn <taphorn@de.ibm.com>
+ * Aron Zeh
+ * Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
#ifndef ZFCP_EXT_H
#define ZFCP_EXT_H
/* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_EXT_REVISION "$Revision: 1.38 $"
+#define ZFCP_EXT_REVISION "$Revision: 1.45 $"
#include "zfcp_def.h"
extern int zfcp_sysfs_unit_create_files(struct device *);
extern void zfcp_sysfs_unit_remove_files(struct device *);
extern void zfcp_sysfs_port_release(struct device *);
-extern int zfcp_sysfs_port_shutdown(struct zfcp_port *);
extern void zfcp_sysfs_unit_release(struct device *);
/**************************** CONFIGURATION *********************************/
extern int zfcp_ccw_register(void);
extern void zfcp_ccw_unregister(void);
-extern int zfcp_initialize_with_0copy(struct zfcp_adapter *);
extern void zfcp_qdio_zero_sbals(struct qdio_buffer **, int, int);
extern int zfcp_qdio_allocate(struct zfcp_adapter *);
extern int zfcp_qdio_allocate_queues(struct zfcp_adapter *);
struct zfcp_fsf_req *);
extern int zfcp_qdio_reqid_check(struct zfcp_adapter *, void *);
+extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_req
+ (struct zfcp_fsf_req *, int, int);
+extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_curr
+ (struct zfcp_fsf_req *);
+extern int zfcp_qdio_sbals_from_sg
+ (struct zfcp_fsf_req *, unsigned long, struct scatterlist *, int, int);
+extern int zfcp_qdio_sbals_from_scsicmnd
+ (struct zfcp_fsf_req *, unsigned long, struct scsi_cmnd *);
+
+
/******************************** FSF ****************************************/
extern int zfcp_fsf_open_port(struct zfcp_erp_action *);
extern int zfcp_fsf_close_port(struct zfcp_erp_action *);
extern int zfcp_fsf_close_unit(struct zfcp_erp_action *);
extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *);
+extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **,
+ u32, u32, struct zfcp_sg_list *);
extern void zfcp_fsf_scsi_er_timeout_handler(unsigned long);
extern int zfcp_fsf_req_dismiss_all(struct zfcp_adapter *);
extern int zfcp_fsf_status_read(struct zfcp_adapter *, int);
-extern int zfcp_fsf_req_create(struct zfcp_adapter *,u32, unsigned long *,
- int, struct zfcp_fsf_req **);
-extern void zfcp_fsf_req_free(struct zfcp_fsf_req *);
-extern int zfcp_fsf_send_generic(struct zfcp_fsf_req *, unsigned char,
- unsigned long *, struct timer_list *);
+extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *,
+ unsigned long *, struct zfcp_fsf_req **);
+extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *,
+ struct zfcp_erp_action *);
+extern int zfcp_fsf_send_els(struct zfcp_send_els *);
extern int zfcp_fsf_req_wait_and_cleanup(struct zfcp_fsf_req *, int, u32 *);
extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *,
- struct zfcp_unit *, Scsi_Cmnd *,
+ struct zfcp_unit *,
+ struct scsi_cmnd *,
int);
extern int zfcp_fsf_req_complete(struct zfcp_fsf_req *);
extern void zfcp_fsf_incoming_els(struct zfcp_fsf_req *);
/******************************** FCP ****************************************/
extern int zfcp_nameserver_enqueue(struct zfcp_adapter *);
-extern int zfcp_nameserver_request(struct zfcp_erp_action *);
-extern void zfcp_fsf_els_processing(struct zfcp_fsf_req *);
+extern int zfcp_ns_gid_pn_request(struct zfcp_erp_action *);
/******************************* SCSI ****************************************/
extern int zfcp_adapter_scsi_register(struct zfcp_adapter *);
extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
-extern void zfcp_scsi_block_requests(struct Scsi_Host *);
-extern int zfcp_create_sbals_from_sg(struct zfcp_fsf_req *,
- Scsi_Cmnd *, char, int, int);
extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t);
extern char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *);
extern void set_host_byte(u32 *, char);
extern void zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *);
extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *);
+extern int zfcp_scsi_command_async(struct zfcp_adapter *,struct zfcp_unit *unit,
+ struct scsi_cmnd *scsi_cmnd);
+extern int zfcp_scsi_command_sync(struct zfcp_unit *unit,
+ struct scsi_cmnd *scsi_cmnd);
+
/******************************** ERP ****************************************/
extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, u32, int);
extern int zfcp_erp_adapter_reopen(struct zfcp_adapter *, int);
extern int zfcp_erp_wait(struct zfcp_adapter *);
extern void zfcp_erp_fsf_req_handler(struct zfcp_fsf_req *);
+extern int zfcp_test_link(struct zfcp_port *);
+
/******************************** AUX ****************************************/
extern void zfcp_cmd_dbf_event_fsf(const char *, struct zfcp_fsf_req *,
void *, int);
-extern void zfcp_cmd_dbf_event_scsi(const char *, Scsi_Cmnd *);
+extern void zfcp_cmd_dbf_event_scsi(const char *, struct scsi_cmnd *);
extern void zfcp_in_els_dbf_event(struct zfcp_adapter *, const char *,
struct fsf_status_read_buffer *, int);
#ifdef ZFCP_STAT_REQSIZES
*
* FCP adapter driver for IBM eServer zSeries
*
- * Copyright 2002 IBM Corporation
+ * (C) Copyright IBM Corp. 2002, 2004
+ *
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com>
- * Aron Zeh <arzeh@de.ibm.com>
- * Wolfgang Taphorn <taphorn@de.ibm.com>
+ * Aron Zeh
+ * Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
*/
/* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_FSF_C_REVISION "$Revision: 1.16 $"
+#define ZFCP_FSF_C_REVISION "$Revision: 1.29 $"
#include "zfcp_ext.h"
static int zfcp_fsf_send_fcp_command_task_management_handler(
struct zfcp_fsf_req *);
static int zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *);
-static int zfcp_fsf_send_generic_handler(struct zfcp_fsf_req *);
static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *);
+static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *);
+static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *);
+static int zfcp_fsf_control_file_handler(struct zfcp_fsf_req *);
static inline int zfcp_fsf_req_create_sbal_check(
unsigned long *, struct zfcp_qdio_queue *, int);
-static struct zfcp_fsf_req *zfcp_fsf_req_get(int, mempool_t *);
-static struct zfcp_fsf_req *zfcp_fsf_req_alloc(struct zfcp_adapter *, u32, int);
+static inline int zfcp_use_one_sbal(
+ struct scatterlist *, int, struct scatterlist *, int);
+static struct zfcp_fsf_req *zfcp_fsf_req_alloc(mempool_t *, int);
static int zfcp_fsf_req_send(struct zfcp_fsf_req *, struct timer_list *);
static int zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *);
static int zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *);
static int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *);
static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *);
static void zfcp_fsf_req_dismiss(struct zfcp_fsf_req *);
+static void zfcp_fsf_req_free(struct zfcp_fsf_req *);
/* association between FSF command and FSF QTCB type */
static u32 fsf_qtcb_type[] = {
[FSF_QTCB_CLOSE_PHYSICAL_PORT] = FSF_SUPPORT_COMMAND,
[FSF_QTCB_SEND_ELS] = FSF_SUPPORT_COMMAND,
[FSF_QTCB_SEND_GENERIC] = FSF_SUPPORT_COMMAND,
- [FSF_QTCB_EXCHANGE_CONFIG_DATA] = FSF_CONFIG_COMMAND
+ [FSF_QTCB_EXCHANGE_CONFIG_DATA] = FSF_CONFIG_COMMAND,
+ [FSF_QTCB_EXCHANGE_PORT_DATA] = FSF_PORT_COMMAND,
+ [FSF_QTCB_DOWNLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND,
+ [FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND
};
/****************************************************************/
/****************************************************************/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_FSF
-#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_FSF
/*
* function: zfcp_fsf_req_alloc
*
*/
static struct zfcp_fsf_req *
-zfcp_fsf_req_alloc(struct zfcp_adapter *adapter, u32 fsf_cmd, int kmalloc_flags)
+zfcp_fsf_req_alloc(mempool_t *pool, int req_flags)
{
+ size_t size;
+ void *ptr;
struct zfcp_fsf_req *fsf_req = NULL;
- switch (fsf_cmd) {
+ if (req_flags & ZFCP_REQ_NO_QTCB)
+ size = sizeof(struct zfcp_fsf_req);
+ else
+ size = sizeof(struct zfcp_fsf_req_pool_element);
- case FSF_QTCB_FCP_CMND:
- case FSF_QTCB_ABORT_FCP_CMND:
- fsf_req = zfcp_fsf_req_get(kmalloc_flags,
- adapter->pool.fcp_command_fsf);
- if (unlikely(fsf_req &&
- (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL))) {
- /*
- * watch low mem buffer
- * Note: If the command is reset or aborted, two
- * timeouts (this and the SCSI ER one) will be started
- * for the command. There is no problem however as
- * the first expired timer will call adapter_reopen
- * which will delete the other
- */
- adapter->pool.fcp_command_fsf_timer.expires =
- jiffies + ZFCP_ERP_SCSI_LOW_MEM_TIMEOUT;
- add_timer(&adapter->pool.fcp_command_fsf_timer);
- }
-#ifdef ZFCP_DEBUG_REQUESTS
- debug_text_event(adapter->req_dbf, 5, "fsfa_fcp");
- if (unlikely(fsf_req &&
- (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL)))
- debug_text_event(adapter->req_dbf, 5, "fsfa_pl");
-#endif /* ZFCP_DEBUG_REQUESTS */
- break;
+ if (likely(pool != NULL))
+ ptr = mempool_alloc(pool, GFP_ATOMIC);
+ else
+ ptr = kmalloc(size, GFP_ATOMIC);
- case FSF_QTCB_OPEN_PORT_WITH_DID:
- case FSF_QTCB_OPEN_LUN:
- case FSF_QTCB_CLOSE_LUN:
- case FSF_QTCB_CLOSE_PORT:
- case FSF_QTCB_CLOSE_PHYSICAL_PORT:
- case FSF_QTCB_SEND_ELS:
- case FSF_QTCB_EXCHANGE_CONFIG_DATA:
- case FSF_QTCB_SEND_GENERIC:
- fsf_req =
- zfcp_fsf_req_get(kmalloc_flags, adapter->pool.erp_fsf);
-#ifdef ZFCP_DEBUG_REQUESTS
- debug_text_event(adapter->req_dbf, 5, "fsfa_erp");
- if (fsf_req && (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL))
- debug_text_event(adapter->req_dbf, 5, "fsfa_pl");
-#endif /* ZFCP_DEBUG_REQUESTS */
- break;
+ if (unlikely(NULL == ptr))
+ goto out;
- case FSF_QTCB_UNSOLICITED_STATUS:
- fsf_req =
- mempool_alloc(adapter->pool.status_read_fsf, GFP_ATOMIC);
- if (fsf_req) {
- memset(fsf_req, 0, sizeof (struct zfcp_fsf_req));
- fsf_req->status |= ZFCP_STATUS_FSFREQ_POOL;
- } else
- ZFCP_LOG_NORMAL("bug: could not find free fsf_req\n");
-#ifdef ZFCP_DEBUG_REQUESTS
- debug_text_event(adapter->req_dbf, 5, "fsfa_sr");
- debug_text_event(adapter->req_dbf, 5, "fsfa_pl");
-#endif /* ZFCP_DEBUG_REQUESTS */
- break;
+ memset(ptr, 0, size);
- default:
- ZFCP_LOG_NORMAL("bug: An attempt to send an unsupported "
- "command has been detected. "
- "(debug info 0x%x)\n", fsf_cmd);
- } //switch(fsf_cmd)
-
- if (unlikely(!fsf_req)) {
- ZFCP_LOG_DEBUG("error: Out of memory. Allocation of FSF "
- "request structure failed\n");
+ if (req_flags & ZFCP_REQ_NO_QTCB) {
+ fsf_req = (struct zfcp_fsf_req *) ptr;
} else {
- ZFCP_LOG_TRACE("FSF request allocated at 0x%lx, "
- "adapter 0x%lx (%s)\n",
- (unsigned long) fsf_req,
- (unsigned long) adapter,
- zfcp_get_busid_by_adapter(adapter));
+ fsf_req = &((struct zfcp_fsf_req_pool_element *) ptr)->fsf_req;
+ fsf_req->qtcb =
+ &((struct zfcp_fsf_req_pool_element *) ptr)->qtcb;
}
-#ifdef ZFCP_DEBUG_REQUESTS
- debug_event(adapter->req_dbf, 5, &fsf_req, sizeof (unsigned long));
- if (likely(fsf_req->qtcb))
- debug_event(adapter->req_dbf, 5, &fsf_req->qtcb,
- sizeof (unsigned long));
-#endif /* ZFCP_DEBUG_REQUESTS */
+ fsf_req->pool = pool;
+ out:
return fsf_req;
}
*
* locks: none
*/
-void
+static void
zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req)
{
- struct zfcp_adapter *adapter = fsf_req->adapter;
-
- switch (fsf_req->fsf_command) {
-
- case FSF_QTCB_FCP_CMND:
- case FSF_QTCB_ABORT_FCP_CMND:
- if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_POOL)) {
- del_timer(&adapter->pool.fcp_command_fsf_timer);
- mempool_free(fsf_req, adapter->pool.fcp_command_fsf);
- } else
- kfree(fsf_req);
- break;
-
- case FSF_QTCB_OPEN_PORT_WITH_DID:
- case FSF_QTCB_OPEN_LUN:
- case FSF_QTCB_CLOSE_LUN:
- case FSF_QTCB_CLOSE_PORT:
- case FSF_QTCB_CLOSE_PHYSICAL_PORT:
- case FSF_QTCB_SEND_ELS:
- case FSF_QTCB_EXCHANGE_CONFIG_DATA:
- case FSF_QTCB_SEND_GENERIC:
- if (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL)
- mempool_free(fsf_req, adapter->pool.erp_fsf);
+ if (likely(fsf_req->pool != NULL))
+ mempool_free(fsf_req, fsf_req->pool);
else
kfree(fsf_req);
- break;
-
- case FSF_QTCB_UNSOLICITED_STATUS:
- mempool_free(fsf_req, adapter->pool.status_read_fsf);
- break;
- }
}
/*
/* log additional information provided by FSF (if any) */
if (unlikely(fsf_req->qtcb->header.log_length)) {
/* do not trust them ;-) */
- if (fsf_req->qtcb->header.log_start > ZFCP_QTCB_SIZE) {
+ if (fsf_req->qtcb->header.log_start > sizeof(struct fsf_qtcb)) {
ZFCP_LOG_NORMAL
("bug: ULP (FSF logging) log data starts "
"beyond end of packet header. Ignored. "
"(start=%i, size=%li)\n",
- fsf_req->qtcb->header.log_start, ZFCP_QTCB_SIZE);
+ fsf_req->qtcb->header.log_start,
+ sizeof(struct fsf_qtcb));
goto forget_log;
}
if ((fsf_req->qtcb->header.log_start +
fsf_req->qtcb->header.log_length)
- > ZFCP_QTCB_SIZE) {
+ > sizeof(struct fsf_qtcb)) {
ZFCP_LOG_NORMAL("bug: ULP (FSF logging) log data ends "
"beyond end of packet header. Ignored. "
"(start=%i, length=%i, size=%li)\n",
fsf_req->qtcb->header.log_start,
fsf_req->qtcb->header.log_length,
- ZFCP_QTCB_SIZE);
+ sizeof(struct fsf_qtcb));
goto forget_log;
}
ZFCP_LOG_TRACE("ULP log data: \n");
(char *) (((unsigned long) fsf_req) & 0xFFFFFF00),
sizeof (struct zfcp_fsf_req));
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, (char *) fsf_req->qtcb,
- ZFCP_QTCB_SIZE);
+ sizeof(struct fsf_qtcb));
debug_text_event(adapter->erp_dbf, 0, "prot_inval:");
debug_exception(adapter->erp_dbf, 0,
&fsf_req->qtcb->prefix.prot_status,
(unsigned long) fsf_req,
(unsigned long) (fsf_req->qtcb));
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
- (char *) fsf_req->qtcb, ZFCP_QTCB_SIZE);
+ (char *) fsf_req->qtcb, sizeof(struct fsf_qtcb));
}
switch (fsf_req->fsf_command) {
case FSF_QTCB_SEND_GENERIC:
ZFCP_LOG_FLAGS(2, "FSF_QTCB_SEND_GENERIC\n");
- zfcp_fsf_send_generic_handler(fsf_req);
- zfcp_erp_fsf_req_handler(fsf_req);
+ zfcp_fsf_send_ct_handler(fsf_req);
break;
case FSF_QTCB_OPEN_PORT_WITH_DID:
ZFCP_LOG_FLAGS(2, "FSF_QTCB_OPEN_PORT_WITH_DID\n");
zfcp_fsf_open_port_handler(fsf_req);
- zfcp_erp_fsf_req_handler(fsf_req);
break;
case FSF_QTCB_OPEN_LUN:
ZFCP_LOG_FLAGS(2, "FSF_QTCB_OPEN_LUN\n");
zfcp_fsf_open_unit_handler(fsf_req);
- zfcp_erp_fsf_req_handler(fsf_req);
break;
case FSF_QTCB_CLOSE_LUN:
ZFCP_LOG_FLAGS(2, "FSF_QTCB_CLOSE_LUN\n");
zfcp_fsf_close_unit_handler(fsf_req);
- zfcp_erp_fsf_req_handler(fsf_req);
break;
case FSF_QTCB_CLOSE_PORT:
ZFCP_LOG_FLAGS(2, "FSF_QTCB_CLOSE_PORT\n");
zfcp_fsf_close_port_handler(fsf_req);
- zfcp_erp_fsf_req_handler(fsf_req);
break;
case FSF_QTCB_CLOSE_PHYSICAL_PORT:
ZFCP_LOG_FLAGS(2, "FSF_QTCB_CLOSE_PHYSICAL_PORT\n");
zfcp_fsf_close_physical_port_handler(fsf_req);
- zfcp_erp_fsf_req_handler(fsf_req);
break;
case FSF_QTCB_EXCHANGE_CONFIG_DATA:
ZFCP_LOG_FLAGS(2, "FSF_QTCB_EXCHANGE_CONFIG_DATA\n");
zfcp_fsf_exchange_config_data_handler(fsf_req);
- zfcp_erp_fsf_req_handler(fsf_req);
+ break;
+
+ case FSF_QTCB_SEND_ELS :
+ ZFCP_LOG_FLAGS(2, "FSF_QTCB_SEND_ELS\n");
+ zfcp_fsf_send_els_handler(fsf_req);
+ break;
+
+ case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
+ ZFCP_LOG_FLAGS(2, "FSF_QTCB_DOWNLOAD_CONTROL_FILE\n");
+ zfcp_fsf_control_file_handler(fsf_req);
+ break;
+
+ case FSF_QTCB_UPLOAD_CONTROL_FILE:
+ ZFCP_LOG_FLAGS(2, "FSF_QTCB_UPLOAD_CONTROL_FILE\n");
+ zfcp_fsf_control_file_handler(fsf_req);
break;
default:
fsf_req->qtcb->header.fsf_command);
}
+ zfcp_erp_fsf_req_handler(fsf_req);
return retval;
}
struct zfcp_fsf_req *fsf_req;
struct fsf_status_read_buffer *status_buffer;
unsigned long lock_flags;
- volatile struct qdio_buffer_element *buffere;
- struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
+ volatile struct qdio_buffer_element *sbale;
int retval = 0;
/* setup new FSF request */
- retval = zfcp_fsf_req_create(adapter,
- FSF_QTCB_UNSOLICITED_STATUS,
- &lock_flags, req_flags, &fsf_req);
+ retval = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS,
+ req_flags | ZFCP_REQ_NO_QTCB,
+ adapter->pool.fsf_req_status_read,
+ &lock_flags, &fsf_req);
if (retval < 0) {
ZFCP_LOG_INFO("error: Out of resources. Could not create an "
"unsolicited status buffer for "
goto failed_req_create;
}
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS;
+ sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY;
+ fsf_req->sbale_curr = 2;
+
status_buffer =
- mempool_alloc(adapter->pool.status_read_buf, GFP_ATOMIC);
+ mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC);
if (!status_buffer) {
ZFCP_LOG_NORMAL("bug: could not get some buffer\n");
goto failed_buf;
fsf_req->data.status_read.buffer = status_buffer;
/* insert pointer to respective buffer */
- buffere = req_queue->buffer[fsf_req->sbal_index]->element;
- buffere[2].addr = (void *) status_buffer;
- buffere[2].length = sizeof (struct fsf_status_read_buffer);
+ sbale = zfcp_qdio_sbale_curr(fsf_req);
+ sbale->addr = (void *) status_buffer;
+ sbale->length = sizeof(struct fsf_status_read_buffer);
/* start QDIO request for this FSF request */
retval = zfcp_fsf_req_send(fsf_req, NULL);
goto out;
failed_req_send:
- mempool_free(status_buffer, adapter->pool.status_read_buf);
+ mempool_free(status_buffer, adapter->pool.data_status_read);
failed_buf:
zfcp_fsf_req_free(fsf_req);
fsf_req->data.status_read.buffer;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
- mempool_free(status_buffer, adapter->pool.status_read_buf);
+ mempool_free(status_buffer, adapter->pool.data_status_read);
zfcp_fsf_req_cleanup(fsf_req);
goto out;
}
case FSF_STATUS_READ_LINK_DOWN:
ZFCP_LOG_FLAGS(1, "FSF_STATUS_READ_LINK_DOWN\n");
+
/* Unneccessary, ignoring.... */
break;
zfcp_erp_adapter_reopen(adapter,
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED
| ZFCP_STATUS_COMMON_ERP_FAILED);
+
+ break;
+
+ case FSF_STATUS_READ_NOTIFICATION_LOST:
+ ZFCP_LOG_FLAGS(1, "FSF_STATUS_READ_NOTIFICATION_LOST\n");
+ debug_text_event(adapter->erp_dbf, 2, "unsol_not_lost:");
+ switch (status_buffer->status_subtype) {
+ case FSF_STATUS_READ_SUB_LOST_CFDC_UPDATED:
+ ZFCP_LOG_NORMAL(
+ "The unsolicited status information about "
+ "CFDC update on the adapter %s is lost "
+ "due to the lack of internal resources\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ case FSF_STATUS_READ_SUB_LOST_CFDC_HARDENED:
+ ZFCP_LOG_NORMAL(
+ "The unsolicited status information about "
+ "CFDC harden on the adapter %s is lost "
+ "due to the lack of internal resources\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ }
+ break;
+
+ case FSF_STATUS_READ_CFDC_UPDATED:
+ ZFCP_LOG_FLAGS(1, "FSF_STATUS_READ_CFDC_UPDATED\n");
+ debug_text_event(adapter->erp_dbf, 2, "unsol_cfdc_update:");
+ ZFCP_LOG_NORMAL(
+ "CFDC has been updated on the adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+
+ case FSF_STATUS_READ_CFDC_HARDENED:
+ ZFCP_LOG_FLAGS(1, "FSF_STATUS_READ_CFDC_HARDENED\n");
+ debug_text_event(adapter->erp_dbf, 2, "unsol_cfdc_harden:");
+ switch (status_buffer->status_subtype) {
+ case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE:
+ ZFCP_LOG_NORMAL(
+ "CFDC of the adapter %s "
+ "has been saved on the SE\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2:
+ ZFCP_LOG_NORMAL(
+ "CFDC of the adapter %s "
+ "has been copied to the secondary SE\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ default:
+ ZFCP_LOG_NORMAL(
+ "CFDC of the adapter %s has been hardened\n",
+ zfcp_get_busid_by_adapter(adapter));
+ }
break;
default:
sizeof (struct fsf_status_read_buffer));
break;
}
- mempool_free(status_buffer, adapter->pool.status_read_buf);
+ mempool_free(status_buffer, adapter->pool.data_status_read);
zfcp_fsf_req_cleanup(fsf_req);
/*
* recycle buffer and start new request repeat until outbound
struct zfcp_adapter *adapter,
struct zfcp_unit *unit, int req_flags)
{
- struct zfcp_fsf_req *new_fsf_req = NULL;
- int retval = 0;
+ volatile struct qdio_buffer_element *sbale;
unsigned long lock_flags;
+ struct zfcp_fsf_req *fsf_req = NULL;
+ int retval = 0;
/* setup new FSF request */
retval = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND,
- &lock_flags, req_flags, &new_fsf_req);
+ req_flags, adapter->pool.fsf_req_abort,
+ &lock_flags, &fsf_req);
if (retval < 0) {
ZFCP_LOG_INFO("error: Out of resources. Could not create an "
"abort command request on the device with "
goto out;
}
- new_fsf_req->data.abort_fcp_command.unit = unit;
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+ fsf_req->data.abort_fcp_command.unit = unit;
/* set handles of unit and its parent port in QTCB */
- new_fsf_req->qtcb->header.lun_handle = unit->handle;
- new_fsf_req->qtcb->header.port_handle = unit->port->handle;
+ fsf_req->qtcb->header.lun_handle = unit->handle;
+ fsf_req->qtcb->header.port_handle = unit->port->handle;
/* set handle of request which should be aborted */
- new_fsf_req->qtcb->bottom.support.req_handle = (u64) old_req_id;
+ fsf_req->qtcb->bottom.support.req_handle = (u64) old_req_id;
/* start QDIO request for this FSF request */
zfcp_fsf_start_scsi_er_timer(adapter);
- retval = zfcp_fsf_req_send(new_fsf_req, NULL);
+ retval = zfcp_fsf_req_send(fsf_req, NULL);
if (retval) {
del_timer(&adapter->scsi_er_timer);
ZFCP_LOG_INFO("error: Could not send an abort command request "
"port WWPN 0x%Lx and unit LUN 0x%Lx\n",
zfcp_get_busid_by_adapter(adapter),
unit->port->wwpn, unit->fcp_lun);
- zfcp_fsf_req_free(new_fsf_req);
- new_fsf_req = NULL;
+ zfcp_fsf_req_free(fsf_req);
+ fsf_req = NULL;
goto out;
}
unit->fcp_lun, old_req_id);
out:
write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
- return new_fsf_req;
+ return fsf_req;
}
/*
return retval;
}
-/*
- * function: zfcp_fsf_send_generic
- *
- * purpose: sends a FC request according to FC-GS-3
- *
- * returns: address of initiated FSF request
- * NULL - request could not be initiated
+/**
+ * zfcp_use_one_sbal - checks whether req buffer and resp bother each fit into
+ * one SBALE
+ * Two scatter-gather lists are passed, one for the reqeust and one for the
+ * response.
+ */
+static inline int
+zfcp_use_one_sbal(struct scatterlist *req, int req_count,
+ struct scatterlist *resp, int resp_count)
+{
+ return ((req_count == 1) &&
+ (resp_count == 1) &&
+ (((unsigned long) zfcp_sg_to_address(&req[0]) &
+ PAGE_MASK) ==
+ ((unsigned long) (zfcp_sg_to_address(&req[0]) +
+ req[0].length - 1) & PAGE_MASK)) &&
+ (((unsigned long) zfcp_sg_to_address(&resp[0]) &
+ PAGE_MASK) ==
+ ((unsigned long) (zfcp_sg_to_address(&resp[0]) +
+ resp[0].length - 1) & PAGE_MASK)));
+}
+
+/**
+ * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS)
+ * @ct: pointer to struct zfcp_send_ct which conatins all needed data for
+ * the request
+ * @pool: pointer to memory pool, if non-null this pool is used to allocate
+ * a struct zfcp_fsf_req
+ * @erp_action: pointer to erp_action, if non-null the Generic Service request
+ * is sent within error recovery
*/
int
-zfcp_fsf_send_generic(struct zfcp_fsf_req *fsf_req, unsigned char timeout,
- unsigned long *lock_flags, struct timer_list *timer)
+zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
+ struct zfcp_erp_action *erp_action)
{
- int retval = 0;
- struct qdio_buffer *buffer;
- volatile struct qdio_buffer_element *buffer_element = NULL;
- struct zfcp_port *port = fsf_req->data.send_generic.port;
- struct zfcp_adapter *adapter = port->adapter;
-
- /* put buffers to the 2 SBALEs after the QTCB */
- buffer = (adapter->request_queue.buffer[fsf_req->sbal_index]);
- buffer_element = &(buffer->element[2]);
- buffer_element->addr = fsf_req->data.send_generic.outbuf;
- buffer_element->length = fsf_req->data.send_generic.outbuf_length;
- buffer_element++;
- buffer_element->addr = fsf_req->data.send_generic.inbuf;
- buffer_element->length = fsf_req->data.send_generic.inbuf_length;
- buffer_element->flags |= SBAL_FLAGS_LAST_ENTRY;
+ volatile struct qdio_buffer_element *sbale;
+ struct zfcp_port *port;
+ struct zfcp_adapter *adapter;
+ struct zfcp_fsf_req *fsf_req;
+ unsigned long lock_flags;
+ int bytes;
+ int ret = 0;
+
+ port = ct->port;
+ adapter = port->adapter;
+
+ ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC,
+ ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
+ pool, &lock_flags, &fsf_req);
+ if (ret < 0) {
+ ZFCP_LOG_INFO("error: out of memory. Could not create CT "
+ "request (FC-GS). (adapter: %s)\n",
+ zfcp_get_busid_by_adapter(adapter));
+ goto failed_req;
+ }
+
+ if (erp_action != NULL) {
+ erp_action->fsf_req = fsf_req;
+ fsf_req->erp_action = erp_action;
+ }
+
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ if (zfcp_use_one_sbal(ct->req, ct->req_count,
+ ct->resp, ct->resp_count)){
+ /* both request buffer and response buffer
+ fit into one sbale each */
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
+ sbale[2].addr = zfcp_sg_to_address(&ct->req[0]);
+ sbale[2].length = ct->req[0].length;
+ sbale[3].addr = zfcp_sg_to_address(&ct->resp[0]);
+ sbale[3].length = ct->resp[0].length;
+ sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
+ } else if (adapter->supported_features &
+ FSF_FEATURE_ELS_CT_CHAINED_SBALS) {
+ /* try to use chained SBALs */
+ bytes = zfcp_qdio_sbals_from_sg(fsf_req,
+ SBAL_FLAGS0_TYPE_WRITE_READ,
+ ct->req, ct->req_count,
+ ZFCP_MAX_SBALS_PER_CT_REQ);
+ if (bytes <= 0) {
+ ZFCP_LOG_INFO("error: out of resources (outbuf). "
+ "Could not create CT request (FC-GS). "
+ "(adapter: %s)\n",
+ zfcp_get_busid_by_adapter(adapter));
+ if (bytes == 0)
+ ret = -ENOMEM;
+ else
+ ret = bytes;
+
+ goto failed_send;
+ }
+ fsf_req->qtcb->bottom.support.req_buf_length = bytes;
+ fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
+ bytes = zfcp_qdio_sbals_from_sg(fsf_req,
+ SBAL_FLAGS0_TYPE_WRITE_READ,
+ ct->resp, ct->resp_count,
+ ZFCP_MAX_SBALS_PER_CT_REQ);
+ if (bytes <= 0) {
+ ZFCP_LOG_INFO("error: out of resources (inbuf). "
+ "Could not create a CT request (FC-GS). "
+ "(adapter: %s)\n",
+ zfcp_get_busid_by_adapter(adapter));
+ if (bytes == 0)
+ ret = -ENOMEM;
+ else
+ ret = bytes;
+
+ goto failed_send;
+ }
+ fsf_req->qtcb->bottom.support.resp_buf_length = bytes;
+ } else {
+ /* reject send generic request */
+ ZFCP_LOG_INFO(
+ "error: microcode does not support chained SBALs."
+ "CT request (FC-GS) too big. (adapter: %s)\n",
+ zfcp_get_busid_by_adapter(adapter));
+ ret = -EOPNOTSUPP;
+ goto failed_send;
+ }
/* settings in QTCB */
fsf_req->qtcb->header.port_handle = port->handle;
fsf_req->qtcb->bottom.support.service_class = adapter->fc_service_class;
- fsf_req->qtcb->bottom.support.timeout = timeout;
+ fsf_req->qtcb->bottom.support.timeout = ct->timeout;
+ fsf_req->data.send_ct = ct;
/* start QDIO request for this FSF request */
- retval = zfcp_fsf_req_send(fsf_req, timer);
- if (retval) {
- ZFCP_LOG_DEBUG("error: Out of resources. could not send a "
- "generic services "
- "command via the adapter %s, port "
- "WWPN 0x%Lx\n",
+ ret = zfcp_fsf_req_send(fsf_req, ct->timer);
+ if (ret) {
+ ZFCP_LOG_DEBUG("error: out of resources. Could not send CT "
+ "request (FC-GS). (adapter: %s, "
+ "port WWPN 0x%Lx)\n",
zfcp_get_busid_by_adapter(adapter), port->wwpn);
- /*
- * fsf_req structure will be cleaned up by higher layer handler
- */
- goto out;
+ goto failed_send;
}
- ZFCP_LOG_DEBUG("Send Generic request initiated "
- "(adapter busido=%s, port d_id=0x%x)\n",
- zfcp_get_busid_by_adapter(adapter),
- (unsigned int) port->d_id);
+ ZFCP_LOG_DEBUG("CT request initiated. (adapter: %s, port WWPN 0x%Lx)\n",
+ zfcp_get_busid_by_adapter(adapter), port->wwpn);
+ goto out;
+
+ failed_send:
+ zfcp_fsf_req_free(fsf_req);
+ if (erp_action != NULL) {
+ erp_action->fsf_req = NULL;
+ }
+ failed_req:
out:
- return retval;
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+ lock_flags);
+ return ret;
}
-/*
- * function: zfcp_fsf_send_generic_handler
- *
- * purpose: is called for finished Send Generic request
+/**
+ * zfcp_fsf_send_ct_handler - handler for Generic Service requests
+ * @fsf_req: pointer to struct zfcp_fsf_req
*
- * returns:
+ * Data specific for the Generic Service request is passed by
+ * fsf_req->data.send_ct
+ * Usually a specific handler for the request is called via
+ * fsf_req->data.send_ct->handler at end of this function.
*/
static int
-zfcp_fsf_send_generic_handler(struct zfcp_fsf_req *fsf_req)
+zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
{
+ struct zfcp_port *port;
+ struct zfcp_adapter *adapter;
+ struct zfcp_send_ct *send_ct;
+ struct fsf_qtcb_header *header;
+ struct fsf_qtcb_bottom_support *bottom;
int retval = -EINVAL;
- struct zfcp_port *port = fsf_req->data.send_generic.port;
+ u16 subtable, rule, counter;
+
+ adapter = fsf_req->adapter;
+ send_ct = fsf_req->data.send_ct;
+ port = send_ct->port;
+ header = &fsf_req->qtcb->header;
+ bottom = &fsf_req->qtcb->bottom.support;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
/* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */
}
/* evaluate FSF status in QTCB */
- switch (fsf_req->qtcb->header.fsf_status) {
+ switch (header->fsf_status) {
- case FSF_PORT_HANDLE_NOT_VALID:
- ZFCP_LOG_FLAGS(1, "FSF_PORT_HANDLE_NOT_VALID\n");
- ZFCP_LOG_DEBUG("Temporary port identifier (handle) 0x%x "
- "for the port with WWPN 0x%Lx connected to "
- "the adapter %s is "
- "not valid. This may happen occasionally.\n",
- port->handle,
- port->wwpn, zfcp_get_busid_by_port(port));
- ZFCP_LOG_INFO("status qualifier:\n");
- ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
- (char *) &fsf_req->qtcb->header.fsf_status_qual,
- sizeof (union fsf_status_qual));
- debug_text_event(fsf_req->adapter->erp_dbf, 1,
- "fsf_s_phandle_nv");
- zfcp_erp_adapter_reopen(port->adapter, 0);
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ case FSF_GOOD :
+ ZFCP_LOG_FLAGS(2,"FSF_GOOD\n");
+ retval = 0;
break;
- case FSF_SERVICE_CLASS_NOT_SUPPORTED:
- ZFCP_LOG_FLAGS(0, "FSF_SERVICE_CLASS_NOT_SUPPORTED\n");
- if (fsf_req->adapter->fc_service_class <= 3) {
- ZFCP_LOG_NORMAL("error: The adapter %s does "
+ case FSF_SERVICE_CLASS_NOT_SUPPORTED :
+ ZFCP_LOG_FLAGS(2, "FSF_SERVICE_CLASS_NOT_SUPPORTED\n");
+ if (adapter->fc_service_class <= 3) {
+ ZFCP_LOG_INFO("error: The adapter %s does "
"not support fibre-channel class %d.\n",
zfcp_get_busid_by_port(port),
- fsf_req->adapter->fc_service_class);
+ adapter->fc_service_class);
} else {
- ZFCP_LOG_NORMAL
- ("bug: The fibre channel class at the adapter "
- "%s is invalid. " "(debug info %d)\n",
+ ZFCP_LOG_INFO("bug: The fibre channel class at the "
+ "adapter %s is invalid. "
+ "(debug info %d)\n",
zfcp_get_busid_by_port(port),
- fsf_req->adapter->fc_service_class);
+ adapter->fc_service_class);
}
/* stop operation for this adapter */
- debug_text_exception(fsf_req->adapter->erp_dbf, 0,
- "fsf_s_class_nsup");
+ debug_text_exception(adapter->erp_dbf, 0, "fsf_s_class_nsup");
zfcp_erp_adapter_shutdown(port->adapter, 0);
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
- case FSF_GENERIC_COMMAND_REJECTED:
- ZFCP_LOG_FLAGS(1, "FSF_GENERIC_COMMAND_REJECTED\n");
+ case FSF_ADAPTER_STATUS_AVAILABLE :
+ ZFCP_LOG_FLAGS(2, "FSF_ADAPTER_STATUS_AVAILABLE\n");
+ switch (header->fsf_status_qual.word[0]){
+ case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE :
+ ZFCP_LOG_FLAGS(2,"FSF_SQ_INVOKE_LINK_TEST_PROCEDURE\n");
+ /* reopening link to port */
+ debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ltest");
+ zfcp_test_link(port);
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ break;
+ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED :
+ ZFCP_LOG_FLAGS(2,"FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED\n");
+ /* ERP strategy will escalate */
+ debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp");
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ break;
+ default:
+ ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x "
+ "arrived.\n",
+ header->fsf_status_qual.word[0]);
+ break;
+ }
+ break;
+
+ case FSF_ACCESS_DENIED:
+ ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n");
+ ZFCP_LOG_NORMAL("Access denied, cannot send generic command "
+ "to a port with WWPN 0x%Lx connected "
+ "to the adapter %s\n", port->wwpn,
+ zfcp_get_busid_by_port(port));
+ counter = 0;
+ do {
+ subtable = header->fsf_status_qual.halfword[counter++];
+ rule = header->fsf_status_qual.halfword[counter++];
+ switch (subtable) {
+ case FSF_SQ_CFDC_SUBTABLE_OS:
+ case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
+ case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
+ case FSF_SQ_CFDC_SUBTABLE_LUN:
+ ZFCP_LOG_NORMAL("Access denied (%s rule %d)\n",
+ zfcp_act_subtable_type[subtable], rule);
+ break;
+ }
+ } while (counter < 4);
+ debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ break;
+
+ case FSF_GENERIC_COMMAND_REJECTED :
+ ZFCP_LOG_FLAGS(2, "FSF_GENERIC_COMMAND_REJECTED\n");
ZFCP_LOG_INFO("warning: The port with WWPN 0x%Lx connected to "
- "the adapter %s is"
+ "the adapter %s has "
"rejected a generic services command.\n",
port->wwpn, zfcp_get_busid_by_port(port));
ZFCP_LOG_INFO("status qualifier:\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
- (char *) &fsf_req->qtcb->header.fsf_status_qual,
+ (char *) &header->fsf_status_qual,
sizeof (union fsf_status_qual));
- debug_text_event(fsf_req->adapter->erp_dbf, 1,
- "fsf_s_gcom_rej");
+ debug_text_event(adapter->erp_dbf, 1, "fsf_s_gcom_rej");
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ break;
+
+ case FSF_PORT_HANDLE_NOT_VALID :
+ ZFCP_LOG_FLAGS(2, "FSF_PORT_HANDLE_NOT_VALID\n");
+ ZFCP_LOG_DEBUG("Temporary port identifier (handle) 0x%x "
+ "for the port with WWPN 0x%Lx connected to "
+ "the adapter %s is "
+ "not valid. This may happen occasionally.\n",
+ port->handle,
+ port->wwpn, zfcp_get_busid_by_port(port));
+ ZFCP_LOG_INFO("status qualifier:\n");
+ ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
+ (char *) &header->fsf_status_qual,
+ sizeof (union fsf_status_qual));
+ debug_text_event(adapter->erp_dbf, 1, "fsf_s_phandle_nv");
+ zfcp_erp_adapter_reopen(port->adapter, 0);
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
- case FSF_REQUEST_BUF_NOT_VALID:
- ZFCP_LOG_FLAGS(1, "FSF_REQUEST_BUF_NOT_VALID\n");
+ case FSF_REQUEST_BUF_NOT_VALID :
+ ZFCP_LOG_FLAGS(2, "FSF_REQUEST_BUF_NOT_VALID\n");
ZFCP_LOG_NORMAL("error: The port with WWPN 0x%Lx connected to "
- "the adapter %s is"
+ "the adapter %s has "
"rejected a generic services command "
"due to invalid request buffer.\n",
port->wwpn, zfcp_get_busid_by_port(port));
- debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_reqiv");
+ debug_text_event(adapter->erp_dbf, 1, "fsf_s_reqiv");
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
- case FSF_RESPONSE_BUF_NOT_VALID:
- ZFCP_LOG_FLAGS(1, "FSF_RESPONSE_BUF_NOT_VALID\n");
+ case FSF_RESPONSE_BUF_NOT_VALID :
+ ZFCP_LOG_FLAGS(2, "FSF_RESPONSE_BUF_NOT_VALID\n");
ZFCP_LOG_NORMAL("error: The port with WWPN 0x%Lx connected to "
- "the adapter %s is"
+ "the adapter %s has "
"rejected a generic services command "
"due to invalid response buffer.\n",
port->wwpn, zfcp_get_busid_by_port(port));
- debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_resiv");
+ debug_text_event(adapter->erp_dbf, 1, "fsf_s_resiv");
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
- case FSF_PORT_BOXED:
+ case FSF_PORT_BOXED :
ZFCP_LOG_FLAGS(2, "FSF_PORT_BOXED\n");
ZFCP_LOG_DEBUG("The remote port "
"with WWPN 0x%Lx on the adapter %s "
"needs to be reopened\n",
port->wwpn, zfcp_get_busid_by_port(port));
- debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_s_pboxed");
+ debug_text_event(adapter->erp_dbf, 2, "fsf_s_pboxed");
zfcp_erp_port_reopen(port, 0);
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
| ZFCP_STATUS_FSFREQ_RETRY;
break;
- case FSF_ADAPTER_STATUS_AVAILABLE:
- ZFCP_LOG_FLAGS(2, "FSF_ADAPTER_STATUS_AVAILABLE\n");
- switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
- case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
- ZFCP_LOG_FLAGS(2,
- "FSF_SQ_INVOKE_LINK_TEST_PROCEDURE\n");
- /* reopening link to port */
- debug_text_event(fsf_req->adapter->erp_dbf, 1,
- "fsf_sq_ltest");
- zfcp_erp_port_forced_reopen(port, 0);
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
- case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
- /* ERP strategy will escalate */
- debug_text_event(fsf_req->adapter->erp_dbf, 1,
- "fsf_sq_ulp");
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
-
- default:
- ZFCP_LOG_NORMAL
- ("bug: Wrong status qualifier 0x%x arrived.\n",
- fsf_req->qtcb->header.fsf_status_qual.word[0]);
- break;
- }
- break;
-
- case FSF_GOOD:
- ZFCP_LOG_FLAGS(2, "FSF_GOOD\n");
- retval = 0;
- break;
-
- default:
+ default :
ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
- "(debug info 0x%x)\n",
- fsf_req->qtcb->header.fsf_status);
- debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_sq_inval:");
- debug_exception(fsf_req->adapter->erp_dbf, 0,
- &fsf_req->qtcb->header.fsf_status_qual.word[0],
- sizeof (u32));
+ "(debug info 0x%x)\n", header->fsf_status);
+ debug_text_event(adapter->erp_dbf, 0, "fsf_sq_inval:");
+ debug_exception(adapter->erp_dbf, 0,
+ &header->fsf_status_qual.word[0], sizeof (u32));
break;
}
- skip_fsfstatus:
- /* callback */
- (fsf_req->data.send_generic.handler)(fsf_req);
+
+skip_fsfstatus:
+ if (send_ct->handler != NULL) {
+ send_ct->handler(send_ct->handler_data);
+ }
+
return retval;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns: address of initiated FSF request
- * NULL - request could not be initiated
+/**
+ * zfcp_fsf_send_els - initiate an ELS command (FC-FS)
+ * @els: pointer to struct zfcp_send_els which contains all needed data for
+ * the command.
*/
int
-zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
+zfcp_fsf_send_els(struct zfcp_send_els *els)
{
- int retval = 0;
+ volatile struct qdio_buffer_element *sbale;
+ struct zfcp_fsf_req *fsf_req;
+ struct zfcp_port *port;
+ struct zfcp_adapter *adapter;
unsigned long lock_flags;
-
- /* setup new FSF request */
- retval = zfcp_fsf_req_create(erp_action->adapter,
- FSF_QTCB_EXCHANGE_CONFIG_DATA,
- &lock_flags,
- ZFCP_REQ_AUTO_CLEANUP,
- &(erp_action->fsf_req));
- if (retval < 0) {
- ZFCP_LOG_INFO("error: Out of resources. Could not create an "
- "exchange configuration data request for"
- "the adapter %s.\n",
- zfcp_get_busid_by_adapter(erp_action->adapter));
- goto out;
+ int bytes;
+ int ret = 0;
+
+ port = els->port;
+ adapter = port->adapter;
+
+ ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS,
+ ZFCP_WAIT_FOR_SBAL|ZFCP_REQ_AUTO_CLEANUP,
+ NULL, &lock_flags, &fsf_req);
+ if (ret < 0) {
+ ZFCP_LOG_INFO("error: out of memory. Could not create ELS "
+ "request. (adapter: %s, port did: 0x%06x)\n",
+ zfcp_get_busid_by_adapter(adapter), port->d_id);
+ goto failed_req;
}
- erp_action->fsf_req->erp_action = erp_action;
- /* no information from us to adapter, set nothing */
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ if (zfcp_use_one_sbal(els->req, els->req_count,
+ els->resp, els->resp_count)){
+ /* both request buffer and response buffer
+ fit into one sbale each */
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
+ sbale[2].addr = zfcp_sg_to_address(&els->req[0]);
+ sbale[2].length = els->req[0].length;
+ sbale[3].addr = zfcp_sg_to_address(&els->resp[0]);
+ sbale[3].length = els->resp[0].length;
+ sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
+ } else if (adapter->supported_features &
+ FSF_FEATURE_ELS_CT_CHAINED_SBALS) {
+ /* try to use chained SBALs */
+ bytes = zfcp_qdio_sbals_from_sg(fsf_req,
+ SBAL_FLAGS0_TYPE_WRITE_READ,
+ els->req, els->req_count,
+ ZFCP_MAX_SBALS_PER_ELS_REQ);
+ if (bytes <= 0) {
+ ZFCP_LOG_INFO("error: out of resources (outbuf). "
+ "Could not create ELS request. "
+ "(adapter: %s, port did: 0x%06x)\n",
+ zfcp_get_busid_by_adapter(adapter),
+ port->d_id);
+ if (bytes == 0) {
+ ret = -ENOMEM;
+ } else {
+ ret = bytes;
+ }
+ goto failed_send;
+ }
+ fsf_req->qtcb->bottom.support.req_buf_length = bytes;
+ fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
+ bytes = zfcp_qdio_sbals_from_sg(fsf_req,
+ SBAL_FLAGS0_TYPE_WRITE_READ,
+ els->resp, els->resp_count,
+ ZFCP_MAX_SBALS_PER_ELS_REQ);
+ if (bytes <= 0) {
+ ZFCP_LOG_INFO("error: out of resources (inbuf). "
+ "Could not create ELS request. "
+ "(adapter: %s, port did: 0x%06x)\n",
+ zfcp_get_busid_by_adapter(adapter),
+ port->d_id);
+ if (bytes == 0) {
+ ret = -ENOMEM;
+ } else {
+ ret = bytes;
+ }
+ goto failed_send;
+ }
+ fsf_req->qtcb->bottom.support.resp_buf_length = bytes;
+ } else {
+ /* reject request */
+ ZFCP_LOG_INFO("error: microcode does not support chained SBALs."
+ "ELS request too big. "
+ "(adapter: %s, port did: 0x%06x)\n",
+ zfcp_get_busid_by_adapter(adapter), port->d_id);
+ ret = -EOPNOTSUPP;
+ goto failed_send;
+ }
+
+ /* settings in QTCB */
+ fsf_req->qtcb->bottom.support.d_id = port->d_id;
+ fsf_req->qtcb->bottom.support.service_class = adapter->fc_service_class;
+ fsf_req->qtcb->bottom.support.timeout = ZFCP_ELS_TIMEOUT;
+ fsf_req->data.send_els = els;
+
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
/* start QDIO request for this FSF request */
- retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
- if (retval) {
- ZFCP_LOG_INFO
- ("error: Could not send an exchange configuration data "
+ ret = zfcp_fsf_req_send(fsf_req, NULL);
+ if (ret) {
+ ZFCP_LOG_DEBUG("error: out of resources. Could not send ELS "
+ "request. (adapter: %s, port WWPN 0x%Lx)\n",
+ zfcp_get_busid_by_adapter(adapter), port->wwpn);
+ goto failed_send;
+ }
+
+ ZFCP_LOG_DEBUG("ELS request initiated (adapter: %s, port WWPN 0x%Lx)\n",
+ zfcp_get_busid_by_adapter(adapter), port->wwpn);
+ goto out;
+
+ failed_send:
+ zfcp_fsf_req_free(fsf_req);
+
+ failed_req:
+ out:
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+ lock_flags);
+
+ return ret;
+}
+
+/**
+ * zfcp_fsf_send_els_handler - handler for ELS commands
+ * @fsf_req: pointer to struct zfcp_fsf_req
+ *
+ * Data specific for the ELS command is passed by
+ * fsf_req->data.send_els
+ * Usually a specific handler for the command is called via
+ * fsf_req->data.send_els->handler at end of this function.
+ */
+static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
+{
+ struct zfcp_adapter *adapter;
+ struct zfcp_port *port;
+ struct fsf_qtcb_header *header;
+ struct fsf_qtcb_bottom_support *bottom;
+ struct zfcp_send_els *send_els;
+ int retval = -EINVAL;
+ u16 subtable, rule, counter;
+
+ adapter = fsf_req->adapter;
+ send_els = fsf_req->data.send_els;
+ port = send_els->port;
+ header = &fsf_req->qtcb->header;
+ bottom = &fsf_req->qtcb->bottom.support;
+
+ if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
+ goto skip_fsfstatus;
+
+ switch (header->fsf_status) {
+
+ case FSF_GOOD:
+ ZFCP_LOG_FLAGS(2, "FSF_GOOD\n");
+ retval = 0;
+ break;
+
+ case FSF_SERVICE_CLASS_NOT_SUPPORTED:
+ ZFCP_LOG_FLAGS(2, "FSF_SERVICE_CLASS_NOT_SUPPORTED\n");
+ if (adapter->fc_service_class <= 3) {
+ ZFCP_LOG_INFO("error: The adapter %s does "
+ "not support fibre-channel class %d.\n",
+ zfcp_get_busid_by_port(port),
+ adapter->fc_service_class);
+ } else {
+ ZFCP_LOG_INFO("bug: The fibre channel class at the "
+ "adapter %s is invalid. "
+ "(debug info %d)\n",
+ zfcp_get_busid_by_port(port),
+ adapter->fc_service_class);
+ }
+ /* stop operation for this adapter */
+ debug_text_exception(adapter->erp_dbf, 0, "fsf_s_class_nsup");
+ zfcp_erp_adapter_shutdown(port->adapter, 0);
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ break;
+
+ case FSF_ADAPTER_STATUS_AVAILABLE:
+ ZFCP_LOG_FLAGS(2, "FSF_ADAPTER_STATUS_AVAILABLE\n");
+ switch (header->fsf_status_qual.word[0]){
+ case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: {
+ ZFCP_LOG_FLAGS(2,"FSF_SQ_INVOKE_LINK_TEST_PROCEDURE\n");
+ debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ltest");
+ if (send_els->ls_code != ZFCP_LS_ADISC)
+ zfcp_test_link(port);
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ break;
+ }
+ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
+ ZFCP_LOG_FLAGS(2,"FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED\n");
+ /* ERP strategy will escalate */
+ debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp");
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ break;
+ case FSF_SQ_RETRY_IF_POSSIBLE:
+ ZFCP_LOG_FLAGS(2, "FSF_SQ_RETRY_IF_POSSIBLE\n");
+ debug_text_event(adapter->erp_dbf, 1, "fsf_sq_retry");
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ break;
+ default:
+ ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x\n",
+ header->fsf_status_qual.word[0]);
+ ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
+ (char*)header->fsf_status_qual.word, 16);
+ }
+ break;
+
+ case FSF_ELS_COMMAND_REJECTED:
+ ZFCP_LOG_FLAGS(2, "FSF_ELS_COMMAND_REJECTED\n");
+ ZFCP_LOG_INFO("The ELS command has been rejected because "
+ "a command filter in the FCP channel prohibited "
+ "sending of the ELS to the SAN "
+ "(adapter: %s, wwpn=0x%016Lx)\n",
+ zfcp_get_busid_by_port(port), port->wwpn);
+
+ break;
+
+ case FSF_PAYLOAD_SIZE_MISMATCH:
+ ZFCP_LOG_FLAGS(2, "FSF_PAYLOAD_SIZE_MISMATCH\n");
+ ZFCP_LOG_INFO(
+ "ELS request size and ELS response size must be either "
+ "both 0, or both greater than 0 "
+ "(adapter: %s, req_buf_length=%d resp_buf_length=%d)\n",
+ zfcp_get_busid_by_port(port),
+ bottom->req_buf_length,
+ bottom->resp_buf_length);
+ break;
+
+ case FSF_REQUEST_SIZE_TOO_LARGE:
+ ZFCP_LOG_FLAGS(2, "FSF_REQUEST_SIZE_TOO_LARGE\n");
+ ZFCP_LOG_INFO(
+ "Length of the ELS request buffer, "
+ "specified in QTCB bottom, "
+ "exceeds the size of the buffers "
+ "that have been allocated for ELS request data "
+ "(adapter: %s, req_buf_length=%d)\n",
+ zfcp_get_busid_by_port(port),
+ bottom->req_buf_length);
+ break;
+
+ case FSF_RESPONSE_SIZE_TOO_LARGE:
+ ZFCP_LOG_FLAGS(2, "FSF_RESPONSE_SIZE_TOO_LARGE\n");
+ ZFCP_LOG_INFO(
+ "Length of the ELS response buffer, "
+ "specified in QTCB bottom, "
+ "exceeds the size of the buffers "
+ "that have been allocated for ELS response data "
+ "(adapter: %s, resp_buf_length=%d)\n",
+ zfcp_get_busid_by_port(port),
+ bottom->resp_buf_length);
+ break;
+
+ case FSF_UNKNOWN_COMMAND:
+ ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_COMMAND\n");
+ ZFCP_LOG_INFO(
+ "FSF command 0x%x is not supported by FCP adapter "
+ "(adapter: %s)\n", fsf_req->fsf_command,
+ zfcp_get_busid_by_port(port));
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ break;
+
+ case FSF_ACCESS_DENIED:
+ ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n");
+ ZFCP_LOG_NORMAL("Access denied, cannot send ELS "
+ "(adapter: %s, wwpn=0x%016Lx)\n",
+ zfcp_get_busid_by_port(port), port->wwpn);
+ counter = 0;
+ do {
+ subtable = header->fsf_status_qual.halfword[counter++];
+ rule = header->fsf_status_qual.halfword[counter++];
+ switch (subtable) {
+ case FSF_SQ_CFDC_SUBTABLE_OS:
+ case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
+ case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
+ case FSF_SQ_CFDC_SUBTABLE_LUN:
+ ZFCP_LOG_NORMAL("Access denied (%s rule %d)\n",
+ zfcp_act_subtable_type[subtable], rule);
+ break;
+ }
+ } while (counter < 4);
+ debug_text_event(adapter->erp_dbf, 1, "fsf_s_access");
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ break;
+
+ default:
+ ZFCP_LOG_NORMAL(
+ "bug: An unknown FSF Status was presented "
+ "(adapter: %s, fsf_status=0x%08x)\n",
+ zfcp_get_busid_by_port(port),
+ header->fsf_status);
+ debug_text_event(adapter->erp_dbf, 0, "fsf_sq_inval");
+ debug_exception(adapter->erp_dbf, 0,
+ &header->fsf_status_qual.word[0], sizeof(u32));
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ break;
+ }
+
+skip_fsfstatus:
+ send_els->status = retval;
+
+ if (send_els->handler != 0)
+ send_els->handler(send_els->handler_data);
+
+ kfree(send_els);
+
+ return retval;
+}
+
+/*
+ * function:
+ *
+ * purpose:
+ *
+ * returns: address of initiated FSF request
+ * NULL - request could not be initiated
+ */
+int
+zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
+{
+ volatile struct qdio_buffer_element *sbale;
+ unsigned long lock_flags;
+ int retval = 0;
+
+ /* setup new FSF request */
+ retval = zfcp_fsf_req_create(erp_action->adapter,
+ FSF_QTCB_EXCHANGE_CONFIG_DATA,
+ ZFCP_REQ_AUTO_CLEANUP,
+ erp_action->adapter->pool.fsf_req_erp,
+ &lock_flags, &(erp_action->fsf_req));
+ if (retval < 0) {
+ ZFCP_LOG_INFO("error: Out of resources. Could not create an "
+ "exchange configuration data request for"
+ "the adapter %s.\n",
+ zfcp_get_busid_by_adapter(erp_action->adapter));
+ goto out;
+ }
+
+ sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
+ erp_action->fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+ erp_action->fsf_req->erp_action = erp_action;
+ erp_action->fsf_req->qtcb->bottom.config.feature_selection =
+ FSF_FEATURE_CFDC;
+
+ /* start QDIO request for this FSF request */
+ retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
+ if (retval) {
+ ZFCP_LOG_INFO
+ ("error: Could not send an exchange configuration data "
"command on the adapter %s\n",
zfcp_get_busid_by_adapter(erp_action->adapter));
zfcp_fsf_req_free(erp_action->fsf_req);
* returns:
*/
static int
-zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) {
+zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
+{
int retval = -EIO;
struct fsf_qtcb_bottom_config *bottom;
struct zfcp_adapter *adapter = fsf_req->adapter;
adapter->fsf_lic_version = bottom->lic_version;
adapter->fc_topology = bottom->fc_topology;
adapter->fc_link_speed = bottom->fc_link_speed;
+ adapter->supported_features = bottom->supported_features;
+
+ if(adapter->supported_features & FSF_FEATURE_HBAAPI_MANAGEMENT){
+ adapter->hardware_version = bottom->hardware_version;
+ /* copy just first 17 bytes */
+ memcpy(adapter->serial_number,
+ bottom->serial_number, 17);
+ EBCASC(adapter->serial_number,
+ sizeof(adapter->serial_number));
+ }
+
ZFCP_LOG_INFO("The adapter %s reported "
"the following characteristics:\n"
"WWNN 0x%16.16Lx, "
zfcp_erp_adapter_shutdown(adapter, 0);
goto skip_fsfstatus;
}
- if (bottom->max_qtcb_size < ZFCP_QTCB_SIZE) {
+ if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) {
ZFCP_LOG_NORMAL("bug: Maximum QTCB size (%d bytes) "
"allowed by the adapter %s "
"is lower than the minimum "
"required by the driver (%ld bytes).\n",
bottom->max_qtcb_size,
zfcp_get_busid_by_adapter(adapter),
- ZFCP_QTCB_SIZE);
+ sizeof(struct fsf_qtcb));
debug_text_event(fsf_req->adapter->erp_dbf, 0,
"qtcb-size");
debug_event(fsf_req->adapter->erp_dbf, 0,
atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
&adapter->status);
retval = 0;
+
break;
+
default:
/* retval is -EIO by default */
debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf-stat-ng");
debug_event(fsf_req->adapter->erp_dbf, 0,
&fsf_req->qtcb->header.fsf_status, sizeof (u32));
- zfcp_erp_adapter_shutdown(adapter, 0);
}
skip_fsfstatus:
return retval;
int
zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
{
- int retval = 0;
+ volatile struct qdio_buffer_element *sbale;
unsigned long lock_flags;
+ int retval = 0;
/* setup new FSF request */
retval = zfcp_fsf_req_create(erp_action->adapter,
FSF_QTCB_OPEN_PORT_WITH_DID,
- &lock_flags,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
- &(erp_action->fsf_req));
+ erp_action->adapter->pool.fsf_req_erp,
+ &lock_flags, &(erp_action->fsf_req));
if (retval < 0) {
ZFCP_LOG_INFO("error: Out of resources. Could not create an "
"open port request for "
goto out;
}
+ sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
+ erp_action->fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
erp_action->fsf_req->qtcb->bottom.support.d_id = erp_action->port->d_id;
atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status);
erp_action->fsf_req->data.open_port.port = erp_action->port;
int retval = -EINVAL;
struct zfcp_port *port;
struct fsf_plogi *plogi;
+ struct fsf_qtcb_header *header;
+ u16 subtable, rule, counter;
port = fsf_req->data.open_port.port;
+ header = &fsf_req->qtcb->header;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
/* don't change port status in our bookkeeping */
}
/* evaluate FSF status in QTCB */
- switch (fsf_req->qtcb->header.fsf_status) {
+ switch (header->fsf_status) {
case FSF_PORT_ALREADY_OPEN:
ZFCP_LOG_FLAGS(0, "FSF_PORT_ALREADY_OPEN\n");
*/
break;
+ case FSF_ACCESS_DENIED:
+ ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n");
+ ZFCP_LOG_NORMAL("Access denied, cannot open port "
+ "with WWPN 0x%Lx connected to the adapter %s\n",
+ port->wwpn, zfcp_get_busid_by_port(port));
+ counter = 0;
+ do {
+ subtable = header->fsf_status_qual.halfword[counter++];
+ rule = header->fsf_status_qual.halfword[counter++];
+ switch (subtable) {
+ case FSF_SQ_CFDC_SUBTABLE_OS:
+ case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
+ case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
+ case FSF_SQ_CFDC_SUBTABLE_LUN:
+ ZFCP_LOG_NORMAL("Access denied (%s rule %d)\n",
+ zfcp_act_subtable_type[subtable], rule);
+ break;
+ }
+ } while (counter < 4);
+ debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
+ zfcp_erp_port_failed(port);
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ break;
+
case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
ZFCP_LOG_FLAGS(1, "FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED\n");
ZFCP_LOG_INFO("error: The FSF adapter is out of resources. "
case FSF_ADAPTER_STATUS_AVAILABLE:
ZFCP_LOG_FLAGS(2, "FSF_ADAPTER_STATUS_AVAILABLE\n");
- switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
+ switch (header->fsf_status_qual.word[0]) {
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
ZFCP_LOG_FLAGS(2,
"FSF_SQ_INVOKE_LINK_TEST_PROCEDURE\n");
default:
ZFCP_LOG_NORMAL
("bug: Wrong status qualifier 0x%x arrived.\n",
- fsf_req->qtcb->header.fsf_status_qual.word[0]);
+ header->fsf_status_qual.word[0]);
debug_text_event(fsf_req->adapter->erp_dbf, 0,
"fsf_sq_inval:");
debug_exception(
fsf_req->adapter->erp_dbf, 0,
- &fsf_req->qtcb->header.fsf_status_qual.word[0],
+ &header->fsf_status_qual.word[0],
sizeof (u32));
break;
}
case FSF_GOOD:
ZFCP_LOG_FLAGS(3, "FSF_GOOD\n");
/* save port handle assigned by FSF */
- port->handle = fsf_req->qtcb->header.port_handle;
+ port->handle = header->port_handle;
ZFCP_LOG_INFO("The remote port (WWPN=0x%Lx) via adapter "
"(busid=%s) was opened, it's "
"port handle is 0x%x\n",
default:
ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
"(debug info 0x%x)\n",
- fsf_req->qtcb->header.fsf_status);
+ header->fsf_status);
debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
debug_exception(fsf_req->adapter->erp_dbf, 0,
- &fsf_req->qtcb->header.fsf_status,
- sizeof (u32));
+ &header->fsf_status, sizeof (u32));
break;
}
int
zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
{
- int retval = 0;
+ volatile struct qdio_buffer_element *sbale;
unsigned long lock_flags;
+ int retval = 0;
/* setup new FSF request */
retval = zfcp_fsf_req_create(erp_action->adapter,
FSF_QTCB_CLOSE_PORT,
- &lock_flags,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
- &(erp_action->fsf_req));
+ erp_action->adapter->pool.fsf_req_erp,
+ &lock_flags, &(erp_action->fsf_req));
if (retval < 0) {
ZFCP_LOG_INFO("error: Out of resources. Could not create a "
"close port request for WWPN 0x%Lx connected to "
goto out;
}
+ sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
+ erp_action->fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status);
erp_action->fsf_req->data.close_port.port = erp_action->port;
erp_action->fsf_req->erp_action = erp_action;
ZFCP_LOG_FLAGS(1, "FSF_PORT_HANDLE_NOT_VALID\n");
ZFCP_LOG_INFO("Temporary port identifier (handle) 0x%x "
"for the port with WWPN 0x%Lx connected to "
- "the adapter %s is"
+ "the adapter %s is "
"not valid. This may happen occasionally.\n",
port->handle,
port->wwpn, zfcp_get_busid_by_port(port));
/* setup new FSF request */
retval = zfcp_fsf_req_create(erp_action->adapter,
FSF_QTCB_CLOSE_PHYSICAL_PORT,
- &lock_flags,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
- &erp_action->fsf_req);
+ erp_action->adapter->pool.fsf_req_erp,
+ &lock_flags, &erp_action->fsf_req);
if (retval < 0) {
ZFCP_LOG_INFO("error: Out of resources. Could not create a "
"close physical port request for "
int retval = -EINVAL;
struct zfcp_port *port;
struct zfcp_unit *unit;
+ struct fsf_qtcb_header *header;
+ u16 subtable, rule, counter;
port = fsf_req->data.close_physical_port.port;
+ header = &fsf_req->qtcb->header;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
/* don't change port status in our bookkeeping */
}
/* evaluate FSF status in QTCB */
- switch (fsf_req->qtcb->header.fsf_status) {
+ switch (header->fsf_status) {
case FSF_PORT_HANDLE_NOT_VALID:
ZFCP_LOG_FLAGS(1, "FSF_PORT_HANDLE_NOT_VALID\n");
zfcp_get_busid_by_port(port));
ZFCP_LOG_DEBUG("status qualifier:\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
- (char *) &fsf_req->qtcb->header.fsf_status_qual,
+ (char *) &header->fsf_status_qual,
sizeof (union fsf_status_qual));
debug_text_event(fsf_req->adapter->erp_dbf, 1,
"fsf_s_phand_nv");
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
+ case FSF_ACCESS_DENIED:
+ ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n");
+ ZFCP_LOG_NORMAL("Access denied, cannot close "
+ "physical port with WWPN 0x%Lx connected to "
+ "the adapter %s\n", port->wwpn,
+ zfcp_get_busid_by_port(port));
+ counter = 0;
+ do {
+ subtable = header->fsf_status_qual.halfword[counter++];
+ rule = header->fsf_status_qual.halfword[counter++];
+ switch (subtable) {
+ case FSF_SQ_CFDC_SUBTABLE_OS:
+ case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
+ case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
+ case FSF_SQ_CFDC_SUBTABLE_LUN:
+ ZFCP_LOG_NORMAL("Access denied (%s rule %d)\n",
+ zfcp_act_subtable_type[subtable], rule);
+ break;
+ }
+ } while (counter < 4);
+ debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ break;
+
case FSF_PORT_BOXED:
ZFCP_LOG_FLAGS(2, "FSF_PORT_BOXED\n");
ZFCP_LOG_DEBUG("The remote port with WWPN 0x%Lx on the adapter "
case FSF_ADAPTER_STATUS_AVAILABLE:
ZFCP_LOG_FLAGS(2, "FSF_ADAPTER_STATUS_AVAILABLE\n");
- switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
+ switch (header->fsf_status_qual.word[0]) {
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
ZFCP_LOG_FLAGS(2,
"FSF_SQ_INVOKE_LINK_TEST_PROCEDURE\n");
default:
ZFCP_LOG_NORMAL
("bug: Wrong status qualifier 0x%x arrived.\n",
- fsf_req->qtcb->header.fsf_status_qual.word[0]);
+ header->fsf_status_qual.word[0]);
debug_text_event(fsf_req->adapter->erp_dbf, 0,
"fsf_sq_inval:");
debug_exception(
fsf_req->adapter->erp_dbf, 0,
- &fsf_req->qtcb->header.fsf_status_qual.word[0],
- sizeof (u32));
+ &header->fsf_status_qual.word[0], sizeof (u32));
break;
}
break;
default:
ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
"(debug info 0x%x)\n",
- fsf_req->qtcb->header.fsf_status);
+ header->fsf_status);
debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
debug_exception(fsf_req->adapter->erp_dbf, 0,
- &fsf_req->qtcb->header.fsf_status,
- sizeof (u32));
+ &header->fsf_status, sizeof (u32));
break;
}
int
zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
{
- int retval = 0;
+ volatile struct qdio_buffer_element *sbale;
unsigned long lock_flags;
+ int retval = 0;
/* setup new FSF request */
retval = zfcp_fsf_req_create(erp_action->adapter,
FSF_QTCB_OPEN_LUN,
- &lock_flags,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
- &(erp_action->fsf_req));
+ erp_action->adapter->pool.fsf_req_erp,
+ &lock_flags, &(erp_action->fsf_req));
if (retval < 0) {
ZFCP_LOG_INFO("error: Out of resources. Could not create an "
"open unit request for FCP-LUN 0x%Lx connected "
goto out;
}
+ sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
+ erp_action->fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
erp_action->fsf_req->qtcb->header.port_handle =
erp_action->port->handle;
erp_action->fsf_req->qtcb->bottom.support.fcp_lun =
atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status);
erp_action->fsf_req->data.open_unit.unit = erp_action->unit;
erp_action->fsf_req->erp_action = erp_action;
+ erp_action->fsf_req->qtcb->bottom.support.option =
+ FSF_OPEN_LUN_SUPPRESS_BOXING;
/* start QDIO request for this FSF request */
retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
{
int retval = -EINVAL;
struct zfcp_unit *unit;
+ struct fsf_qtcb_header *header;
+ u16 subtable, rule, counter;
unit = fsf_req->data.open_unit.unit;
+ header = &fsf_req->qtcb->header;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
/* don't change unit status in our bookkeeping */
}
/* evaluate FSF status in QTCB */
- switch (fsf_req->qtcb->header.fsf_status) {
+ switch (header->fsf_status) {
case FSF_PORT_HANDLE_NOT_VALID:
ZFCP_LOG_FLAGS(1, "FSF_PORT_HANDLE_NOT_VALID\n");
ZFCP_LOG_INFO("Temporary port identifier (handle) 0x%x "
"for the port with WWPN 0x%Lx connected to "
- "the adapter %s is"
+ "the adapter %s is "
"not valid. This may happen occasionally.\n",
unit->port->handle,
unit->port->wwpn, zfcp_get_busid_by_unit(unit));
ZFCP_LOG_DEBUG("status qualifier:\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
- (char *) &fsf_req->qtcb->header.fsf_status_qual,
+ (char *) &header->fsf_status_qual,
sizeof (union fsf_status_qual));
debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_ph_nv");
zfcp_erp_adapter_reopen(unit->port->adapter, 0);
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
+ case FSF_ACCESS_DENIED:
+ ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n");
+ ZFCP_LOG_NORMAL("Access denied, cannot open unit "
+ "with FCP-LUN 0x%Lx at the remote port with "
+ "WWPN 0x%Lx connected to the adapter %s\n",
+ unit->fcp_lun, unit->port->wwpn,
+ zfcp_get_busid_by_unit(unit));
+ counter = 0;
+ do {
+ subtable = header->fsf_status_qual.halfword[counter++];
+ rule = header->fsf_status_qual.halfword[counter++];
+ switch (subtable) {
+ case FSF_SQ_CFDC_SUBTABLE_OS:
+ case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
+ case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
+ case FSF_SQ_CFDC_SUBTABLE_LUN:
+ ZFCP_LOG_NORMAL("Access denied (%s rule %d)\n",
+ zfcp_act_subtable_type[subtable], rule);
+ break;
+ }
+ } while (counter < 4);
+ debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
+ zfcp_erp_unit_failed(unit);
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ break;
+
case FSF_PORT_BOXED:
ZFCP_LOG_FLAGS(2, "FSF_PORT_BOXED\n");
ZFCP_LOG_DEBUG("The remote port "
ZFCP_STATUS_FSFREQ_RETRY;
break;
- case FSF_LUN_IN_USE:
- ZFCP_LOG_FLAGS(0, "FSF_LUN_IN_USE\n");
+ case FSF_LUN_SHARING_VIOLATION :
+ ZFCP_LOG_FLAGS(2, "FSF_LUN_SHARING_VIOLATION\n");
ZFCP_LOG_NORMAL("error: FCP-LUN 0x%Lx at "
"the remote port with WWPN 0x%Lx connected "
"to the adapter %s "
unit->fcp_lun,
unit->port->wwpn,
zfcp_get_busid_by_unit(unit));
+ subtable = header->fsf_status_qual.halfword[4];
+ rule = header->fsf_status_qual.halfword[5];
+ switch (subtable) {
+ case FSF_SQ_CFDC_SUBTABLE_OS:
+ case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
+ case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
+ case FSF_SQ_CFDC_SUBTABLE_LUN:
+ ZFCP_LOG_NORMAL("Access denied (%s rule %d)\n",
+ zfcp_act_subtable_type[subtable], rule);
+ break;
+ }
ZFCP_LOG_NORMAL("Additional sense data is presented:\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
- (char *) &fsf_req->qtcb->header.fsf_status_qual,
+ (char *) &header->fsf_status_qual,
sizeof (union fsf_status_qual));
debug_text_event(fsf_req->adapter->erp_dbf, 2,
- "fsf_s_l_in_use");
+ "fsf_s_l_sh_vio");
zfcp_erp_unit_failed(unit);
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
ZFCP_LOG_FLAGS(2, "FSF_ADAPTER_STATUS_AVAILABLE\n");
- switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
+ switch (header->fsf_status_qual.word[0]) {
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
ZFCP_LOG_FLAGS(2,
"FSF_SQ_INVOKE_LINK_TEST_PROCEDURE\n");
default:
ZFCP_LOG_NORMAL
("bug: Wrong status qualifier 0x%x arrived.\n",
- fsf_req->qtcb->header.fsf_status_qual.word[0]);
+ header->fsf_status_qual.word[0]);
debug_text_event(fsf_req->adapter->erp_dbf, 0,
"fsf_sq_inval:");
- debug_exception(
- fsf_req->adapter->erp_dbf, 0,
- &fsf_req->qtcb->header.fsf_status_qual.word[0],
+ debug_exception(fsf_req->adapter->erp_dbf, 0,
+ &header->fsf_status_qual.word[0],
sizeof (u32));
}
break;
case FSF_GOOD:
ZFCP_LOG_FLAGS(3, "FSF_GOOD\n");
/* save LUN handle assigned by FSF */
- unit->handle = fsf_req->qtcb->header.lun_handle;
+ unit->handle = header->lun_handle;
ZFCP_LOG_TRACE("unit (FCP_LUN=0x%Lx) of remote port "
"(WWPN=0x%Lx) via adapter (busid=%s) opened, "
"port handle 0x%x \n",
default:
ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
"(debug info 0x%x)\n",
- fsf_req->qtcb->header.fsf_status);
+ header->fsf_status);
debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
debug_exception(fsf_req->adapter->erp_dbf, 0,
- &fsf_req->qtcb->header.fsf_status,
- sizeof (u32));
+ &header->fsf_status, sizeof (u32));
break;
}
int
zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
{
- int retval = 0;
+ volatile struct qdio_buffer_element *sbale;
unsigned long lock_flags;
+ int retval = 0;
/* setup new FSF request */
retval = zfcp_fsf_req_create(erp_action->adapter,
FSF_QTCB_CLOSE_LUN,
- &lock_flags,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
- &(erp_action->fsf_req));
+ erp_action->adapter->pool.fsf_req_erp,
+ &lock_flags, &(erp_action->fsf_req));
if (retval < 0) {
ZFCP_LOG_INFO("error: Out of resources. Could not create a "
"close unit request for FCP-LUN 0x%Lx "
goto out;
}
+ sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
+ erp_action->fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
erp_action->fsf_req->qtcb->header.port_handle =
erp_action->port->handle;
erp_action->fsf_req->qtcb->header.lun_handle = erp_action->unit->handle;
int
zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
struct zfcp_unit *unit,
- Scsi_Cmnd * scsi_cmnd, int req_flags)
+ struct scsi_cmnd * scsi_cmnd, int req_flags)
{
struct zfcp_fsf_req *fsf_req = NULL;
struct fcp_cmnd_iu *fcp_cmnd_iu;
- volatile struct qdio_buffer_element *buffere;
unsigned int sbtype;
unsigned long lock_flags;
int real_bytes = 0;
int retval = 0;
/* setup new FSF request */
-
- retval = zfcp_fsf_req_create(adapter,
- FSF_QTCB_FCP_CMND,
- &lock_flags, req_flags, &(fsf_req));
+ retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
+ adapter->pool.fsf_req_scsi,
+ &lock_flags, &fsf_req);
if (unlikely(retval < 0)) {
ZFCP_LOG_DEBUG("error: Out of resources. Could not create an "
"FCP command request for FCP-LUN 0x%Lx "
* data direction bits in FCP_CMND IU
*/
switch (scsi_cmnd->sc_data_direction) {
- case SCSI_DATA_NONE:
- ZFCP_LOG_FLAGS(3, "SCSI_DATA_NONE\n");
+ case DMA_NONE:
+ ZFCP_LOG_FLAGS(3, "DMA_NONE\n");
fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
/*
* FIXME(qdio):
*/
sbtype = SBAL_FLAGS0_TYPE_READ;
break;
- case SCSI_DATA_READ:
- ZFCP_LOG_FLAGS(3, "SCSI_DATA_READ\n");
+ case DMA_FROM_DEVICE:
+ ZFCP_LOG_FLAGS(3, "DMA_FROM_DEVICE\n");
fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
sbtype = SBAL_FLAGS0_TYPE_READ;
fcp_cmnd_iu->rddata = 1;
break;
- case SCSI_DATA_WRITE:
- ZFCP_LOG_FLAGS(3, "SCSI_DATA_WRITE\n");
+ case DMA_TO_DEVICE:
+ ZFCP_LOG_FLAGS(3, "DMA_TO_DEVICE\n");
fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
sbtype = SBAL_FLAGS0_TYPE_WRITE;
fcp_cmnd_iu->wddata = 1;
break;
- case SCSI_DATA_UNKNOWN:
- ZFCP_LOG_FLAGS(0, "SCSI_DATA_UNKNOWN not supported\n");
+ case DMA_BIDIRECTIONAL:
+ ZFCP_LOG_FLAGS(0, "DMA_BIDIRECTIONAL not supported\n");
default:
/*
* dummy, catch this condition earlier
*/
goto failed_scsi_cmnd;
}
- buffere =
- &(adapter->request_queue.buffer[fsf_req->sbal_index]->element[0]);
- buffere->flags |= sbtype;
/* set FC service class in QTCB (3 per default) */
fsf_req->qtcb->bottom.io.service_class = adapter->fc_service_class;
fcp_cmnd_iu->add_fcp_cdb_length + sizeof (fcp_dl_t);
/* generate SBALEs from data buffer */
- real_bytes = zfcp_create_sbals_from_sg(fsf_req,
- scsi_cmnd,
- sbtype,
- 0, ZFCP_MAX_SBALS_PER_REQ);
- /* Note: >= and not = because the combined scatter-gather entries
- * may be larger than request_bufflen according to the mailing list
- */
- if (likely(real_bytes >= scsi_cmnd->request_bufflen)) {
- ZFCP_LOG_TRACE("Data fits\n");
- } else if (likely(real_bytes == 0)) {
- ZFCP_LOG_DEBUG("Data did not fit into available buffer(s), "
+ real_bytes = zfcp_qdio_sbals_from_scsicmnd(fsf_req, sbtype, scsi_cmnd);
+ if (unlikely(real_bytes < 0)) {
+ if (fsf_req->sbal_number < ZFCP_MAX_SBALS_PER_REQ) {
+ ZFCP_LOG_DEBUG(
+ "Data did not fit into available buffer(s), "
"waiting for more...\n");
retval = -EIO;
- goto no_fit;
} else {
ZFCP_LOG_NORMAL("error: No truncation implemented but "
- "required. Shutting down unit (busid=%s, "
- "WWPN=0x%16.16Lx, FCP_LUN=0x%16.16Lx)\n",
+ "required. Shutting down unit "
+ "(busid=%s, WWPN=0x%16.16Lx, "
+ "FCP_LUN=0x%16.16Lx)\n",
zfcp_get_busid_by_unit(unit),
unit->port->wwpn,
unit->fcp_lun);
zfcp_erp_unit_shutdown(unit, 0);
retval = -EINVAL;
+ }
goto no_fit;
}
int retval = 0;
struct fcp_cmnd_iu *fcp_cmnd_iu;
unsigned long lock_flags;
- volatile struct qdio_buffer_element *buffere;
+ volatile struct qdio_buffer_element *sbale;
/* setup new FSF request */
- retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND,
- &lock_flags, req_flags, &(fsf_req));
+ retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
+ adapter->pool.fsf_req_scsi,
+ &lock_flags, &fsf_req);
if (retval < 0) {
ZFCP_LOG_INFO("error: Out of resources. Could not create an "
"FCP command (task management) request for "
fsf_req->qtcb->bottom.io.fcp_cmnd_length =
sizeof (struct fcp_cmnd_iu) + sizeof (fcp_dl_t);
- buffere =
- &(adapter->request_queue.buffer[fsf_req->sbal_index]->element[0]);
- buffere[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
- buffere[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
/* set FCP related fields in FCP_CMND IU in QTCB */
fcp_cmnd_iu = (struct fcp_cmnd_iu *)
{
int retval = -EINVAL;
struct zfcp_unit *unit;
+ struct fsf_qtcb_header *header;
+ u16 subtable, rule, counter;
+
+ header = &fsf_req->qtcb->header;
if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT))
unit = fsf_req->data.send_fcp_command_task_management.unit;
}
/* evaluate FSF status in QTCB */
- switch (fsf_req->qtcb->header.fsf_status) {
+ switch (header->fsf_status) {
case FSF_PORT_HANDLE_NOT_VALID:
ZFCP_LOG_FLAGS(1, "FSF_PORT_HANDLE_NOT_VALID\n");
unit->port->handle,
unit->port->wwpn, zfcp_get_busid_by_unit(unit));
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
- (char *) &fsf_req->qtcb->header.fsf_status_qual,
+ (char *) &header->fsf_status_qual,
sizeof (union fsf_status_qual));
debug_text_event(fsf_req->adapter->erp_dbf, 1,
"fsf_s_phand_nv");
zfcp_get_busid_by_unit(unit));
ZFCP_LOG_NORMAL("Status qualifier data:\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
- (char *) &fsf_req->qtcb->header.fsf_status_qual,
+ (char *) &header->fsf_status_qual,
sizeof (union fsf_status_qual));
debug_text_event(fsf_req->adapter->erp_dbf, 1,
"fsf_s_uhand_nv");
zfcp_get_busid_by_unit(unit));
ZFCP_LOG_NORMAL("status qualifier:\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
- (char *) &fsf_req->qtcb->header.fsf_status_qual,
+ (char *) &header->fsf_status_qual,
sizeof (union fsf_status_qual));
debug_text_event(fsf_req->adapter->erp_dbf, 1,
"fsf_s_hand_mis");
zfcp_erp_adapter_reopen(unit->port->adapter, 0);
zfcp_cmd_dbf_event_fsf("handmism",
fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
+ &header->fsf_status_qual,
sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
zfcp_cmd_dbf_event_fsf("unsclass",
fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
+ &header->fsf_status_qual,
sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
unit->handle);
ZFCP_LOG_DEBUG("status qualifier:\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
- (char *) &fsf_req->qtcb->header.fsf_status_qual,
+ (char *) &header->fsf_status_qual,
sizeof (union fsf_status_qual));
debug_text_event(fsf_req->adapter->erp_dbf, 1,
"fsf_s_fcp_lun_nv");
zfcp_erp_port_reopen(unit->port, 0);
zfcp_cmd_dbf_event_fsf("fluninv",
fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
+ &header->fsf_status_qual,
sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
+ case FSF_ACCESS_DENIED:
+ ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n");
+ ZFCP_LOG_NORMAL("Access denied, cannot send FCP "
+ "command to the unit with FCP-LUN 0x%Lx at the "
+ "remote port with WWPN 0x%Lx connected to the "
+ "adapter %s\n", unit->fcp_lun, unit->port->wwpn,
+ zfcp_get_busid_by_unit(unit));
+ counter = 0;
+ do {
+ subtable = header->fsf_status_qual.halfword[counter++];
+ rule = header->fsf_status_qual.halfword[counter++];
+ switch (subtable) {
+ case FSF_SQ_CFDC_SUBTABLE_OS:
+ case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
+ case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
+ case FSF_SQ_CFDC_SUBTABLE_LUN:
+ ZFCP_LOG_NORMAL("Access denied (%s rule %d)\n",
+ zfcp_act_subtable_type[subtable], rule);
+ break;
+ }
+ } while (counter < 4);
+ debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ break;
+
case FSF_DIRECTION_INDICATOR_NOT_VALID:
ZFCP_LOG_FLAGS(0, "FSF_DIRECTION_INDICATOR_NOT_VALID\n");
ZFCP_LOG_INFO("bug: Invalid data direction given for the unit "
zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
zfcp_cmd_dbf_event_fsf("dirinv",
fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
+ &header->fsf_status_qual,
sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
zfcp_cmd_dbf_event_fsf("idleninv",
fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
+ &header->fsf_status_qual,
sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
"fsf_s_out_dl_nv");
zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
zfcp_cmd_dbf_event_fsf("odleninv", fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
+ &header->fsf_status_qual,
sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
zfcp_cmd_dbf_event_fsf("cleninv",
fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
+ &header->fsf_status_qual,
sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_s_pboxed");
zfcp_erp_port_reopen(unit->port, 0);
zfcp_cmd_dbf_event_fsf("portbox", fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
+ &header->fsf_status_qual,
sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
ZFCP_STATUS_FSFREQ_RETRY;
break;
+ case FSF_LUN_BOXED:
+ ZFCP_LOG_FLAGS(0, "FSF_LUN_BOXED\n");
+ ZFCP_LOG_NORMAL(
+ "The remote unit with FCP-LUN 0x%Lx "
+ "at the remote port with WWPN 0x%Lx "
+ "connected to the adapter %s needs to be reopened\n",
+ unit->fcp_lun, unit->port->wwpn,
+ zfcp_get_busid_by_unit(unit));
+ debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_lboxed");
+ zfcp_erp_unit_reopen(unit, 0);
+ zfcp_cmd_dbf_event_fsf("unitbox", fsf_req,
+ &header->fsf_status_qual,
+ sizeof(union fsf_status_qual));
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
+ | ZFCP_STATUS_FSFREQ_RETRY;
+ break;
+
case FSF_ADAPTER_STATUS_AVAILABLE:
ZFCP_LOG_FLAGS(2, "FSF_ADAPTER_STATUS_AVAILABLE\n");
- switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
+ switch (header->fsf_status_qual.word[0]) {
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
ZFCP_LOG_FLAGS(2,
"FSF_SQ_INVOKE_LINK_TEST_PROCEDURE\n");
zfcp_cmd_dbf_event_fsf(
"sqltest",
fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
+ &header->fsf_status_qual,
sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
zfcp_cmd_dbf_event_fsf(
"sqdeperp",
fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
+ &header->fsf_status_qual,
sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
/* FIXME: shall we consider this a successful transfer? */
ZFCP_LOG_NORMAL
("bug: Wrong status qualifier 0x%x arrived.\n",
- fsf_req->qtcb->header.fsf_status_qual.word[0]);
+ header->fsf_status_qual.word[0]);
debug_text_event(fsf_req->adapter->erp_dbf, 0,
"fsf_sq_inval:");
- debug_exception(
- fsf_req->adapter->erp_dbf,
- 0,
- &fsf_req->qtcb->header.fsf_status_qual.word[0],
- sizeof (u32));
+ debug_exception(fsf_req->adapter->erp_dbf, 0,
+ &header->fsf_status_qual.word[0],
+ sizeof(u32));
break;
}
break;
default:
debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
debug_exception(fsf_req->adapter->erp_dbf, 0,
- &fsf_req->qtcb->header.fsf_status,
- sizeof (u32));
+ &header->fsf_status, sizeof(u32));
break;
}
zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
{
int retval = 0;
-
- Scsi_Cmnd *scpnt;
+ struct scsi_cmnd *scpnt;
struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
&(fsf_req->qtcb->bottom.io.fcp_rsp);
struct fcp_cmnd_iu *fcp_cmnd_iu = (struct fcp_cmnd_iu *)
return retval;
}
+
+/*
+ * function: zfcp_fsf_control_file
+ *
+ * purpose: Initiator of the control file upload/download FSF requests
+ *
+ * returns: 0 - FSF request is successfuly created and queued
+ * -EOPNOTSUPP - The FCP adapter does not have Control File support
+ * -EINVAL - Invalid direction specified
+ * -ENOMEM - Insufficient memory
+ * -EPERM - Cannot create FSF request or or place it in QDIO queue
+ */
+int
+zfcp_fsf_control_file(struct zfcp_adapter *adapter,
+ struct zfcp_fsf_req **fsf_req_ptr,
+ u32 fsf_command,
+ u32 option,
+ struct zfcp_sg_list *sg_list)
+{
+ struct zfcp_fsf_req *fsf_req;
+ struct fsf_qtcb_bottom_support *bottom;
+ volatile struct qdio_buffer_element *sbale;
+ unsigned long lock_flags;
+ int req_flags = 0;
+ int direction;
+ int retval = 0;
+
+#if 0
+ if (!(adapter->features & FSF_FEATURE_CFDC)) {
+ ZFCP_LOG_INFO(
+ "Adapter %s does not support control file\n",
+ zfcp_get_busid_by_adapter(adapter));
+ retval = -EOPNOTSUPP;
+ goto no_act_support;
+ }
+#endif
+
+ switch (fsf_command) {
+
+ case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
+ direction = SBAL_FLAGS0_TYPE_WRITE;
+ if ((option != FSF_CFDC_OPTION_FULL_ACCESS) &&
+ (option != FSF_CFDC_OPTION_RESTRICTED_ACCESS))
+ req_flags = ZFCP_WAIT_FOR_SBAL;
+ break;
+
+ case FSF_QTCB_UPLOAD_CONTROL_FILE:
+ direction = SBAL_FLAGS0_TYPE_READ;
+ break;
+
+ default:
+ ZFCP_LOG_INFO("Invalid FSF command code 0x%08x\n", fsf_command);
+ goto invalid_command;
+ }
+
+ retval = zfcp_fsf_req_create(adapter, fsf_command, req_flags,
+ NULL, &lock_flags, &fsf_req);
+ if (retval < 0) {
+ ZFCP_LOG_INFO("error: Could not create FSF request for the "
+ "adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ retval = -EPERM;
+ goto out;
+ }
+
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale[0].flags |= direction;
+
+ bottom = &fsf_req->qtcb->bottom.support;
+ bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
+ bottom->option = option;
+
+ if (sg_list->count > 0) {
+ int bytes;
+
+ bytes = zfcp_qdio_sbals_from_sg(fsf_req, direction,
+ sg_list->sg, sg_list->count,
+ ZFCP_MAX_SBALS_PER_REQ);
+ if (bytes != ZFCP_CFDC_MAX_CONTROL_FILE_SIZE) {
+ ZFCP_LOG_INFO(
+ "error: Could not create sufficient number of "
+ "SBALS for an FSF request to the adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ retval = -ENOMEM;
+ goto sbals_failed;
+ }
+ } else {
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+ }
+
+ retval = zfcp_fsf_req_send(fsf_req, NULL);
+ if (retval < 0) {
+ ZFCP_LOG_INFO(
+ "error: Could not send FSF request to the adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ retval = -EPERM;
+ goto queue_failed;
+ }
+
+ ZFCP_LOG_NORMAL(
+ "Control file %s FSF request has been sent to the adapter %s\n",
+ fsf_command == FSF_QTCB_DOWNLOAD_CONTROL_FILE ?
+ "download" : "upload",
+ zfcp_get_busid_by_adapter(adapter));
+
+ *fsf_req_ptr = fsf_req;
+
+ goto out;
+
+sbals_failed:
+queue_failed:
+ zfcp_fsf_req_free(fsf_req);
+
+out:
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
+
+invalid_command:
+ return retval;
+}
+
+
+/*
+ * function: zfcp_fsf_control_file_handler
+ *
+ * purpose: Handler of the control file upload/download FSF requests
+ *
+ * returns: 0 - FSF request successfuly processed
+ * -EAGAIN - Operation has to be repeated because of a temporary problem
+ * -EACCES - There is no permission to execute an operation
+ * -EPERM - The control file is not in a right format
+ * -EIO - There is a problem with the FCP adapter
+ * -EINVAL - Invalid operation
+ * -EFAULT - User space memory I/O operation fault
+ */
+static int
+zfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req)
+{
+ struct zfcp_adapter *adapter = fsf_req->adapter;
+ struct fsf_qtcb_header *header = &fsf_req->qtcb->header;
+ struct fsf_qtcb_bottom_support *bottom = &fsf_req->qtcb->bottom.support;
+ int retval = 0;
+
+ if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
+ retval = -EINVAL;
+ goto skip_fsfstatus;
+ }
+
+ switch (header->fsf_status) {
+
+ case FSF_GOOD:
+ ZFCP_LOG_FLAGS(2, "FSF_GOOD\n");
+ ZFCP_LOG_NORMAL(
+ "The FSF request has been successfully completed "
+ "on the adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+
+ case FSF_OPERATION_PARTIALLY_SUCCESSFUL:
+ ZFCP_LOG_FLAGS(2, "FSF_OPERATION_PARTIALLY_SUCCESSFUL\n");
+ if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) {
+ switch (header->fsf_status_qual.word[0]) {
+
+ case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE:
+ ZFCP_LOG_NORMAL(
+ "CFDC of the adapter %s could not "
+ "be saved on the SE\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+
+ case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2:
+ ZFCP_LOG_NORMAL(
+ "CFDC of the adapter %s could not "
+ "be copied to the secondary SE\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+
+ default:
+ ZFCP_LOG_NORMAL(
+ "CFDC could not be hardened "
+ "on the adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ }
+ }
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ retval = -EAGAIN;
+ break;
+
+ case FSF_AUTHORIZATION_FAILURE:
+ ZFCP_LOG_FLAGS(2, "FSF_AUTHORIZATION_FAILURE\n");
+ ZFCP_LOG_NORMAL(
+ "Adapter %s does not accept privileged commands\n",
+ zfcp_get_busid_by_adapter(adapter));
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ retval = -EACCES;
+ break;
+
+ case FSF_CFDC_ERROR_DETECTED:
+ ZFCP_LOG_FLAGS(2, "FSF_CFDC_ERROR_DETECTED\n");
+ ZFCP_LOG_NORMAL(
+ "Error at position %d in the CFDC, "
+ "CFDC is discarded by the adapter %s\n",
+ header->fsf_status_qual.word[0],
+ zfcp_get_busid_by_adapter(adapter));
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ retval = -EPERM;
+ break;
+
+ case FSF_CONTROL_FILE_UPDATE_ERROR:
+ ZFCP_LOG_FLAGS(2, "FSF_CONTROL_FILE_UPDATE_ERROR\n");
+ ZFCP_LOG_NORMAL(
+ "Adapter %s cannot harden the control file, "
+ "file is discarded\n",
+ zfcp_get_busid_by_adapter(adapter));
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ retval = -EIO;
+ break;
+
+ case FSF_CONTROL_FILE_TOO_LARGE:
+ ZFCP_LOG_FLAGS(2, "FSF_CONTROL_FILE_TOO_LARGE\n");
+ ZFCP_LOG_NORMAL(
+ "Control file is too large, file is discarded "
+ "by the adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ retval = -EIO;
+ break;
+
+ case FSF_ACCESS_CONFLICT_DETECTED:
+ ZFCP_LOG_FLAGS(2, "FSF_ACCESS_CONFLICT_DETECTED\n");
+ if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE)
+ ZFCP_LOG_NORMAL(
+ "CFDC has been discarded by the adapter %s, "
+ "because activation would impact "
+ "%d active connection(s)\n",
+ zfcp_get_busid_by_adapter(adapter),
+ header->fsf_status_qual.word[0]);
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ retval = -EIO;
+ break;
+
+ case FSF_CONFLICTS_OVERRULED:
+ ZFCP_LOG_FLAGS(2, "FSF_CONFLICTS_OVERRULED\n");
+ if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE)
+ ZFCP_LOG_NORMAL(
+ "CFDC has been activated on the adapter %s, "
+ "but activation has impacted "
+ "%d active connection(s)\n",
+ zfcp_get_busid_by_adapter(adapter),
+ header->fsf_status_qual.word[0]);
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ retval = -EIO;
+ break;
+
+ case FSF_UNKNOWN_COMMAND:
+ ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_COMMAND\n");
+ ZFCP_LOG_NORMAL(
+ "FSF command 0x%x is not supported by the adapter %s\n",
+ fsf_req->fsf_command,
+ zfcp_get_busid_by_adapter(adapter));
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ retval = -EINVAL;
+ break;
+
+ case FSF_UNKNOWN_OP_SUBTYPE:
+ ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_OP_SUBTYPE\n");
+ ZFCP_LOG_NORMAL(
+ "Invalid operation subtype 0x%x has been specified "
+ "in QTCB bottom sent to the adapter %s\n",
+ bottom->operation_subtype,
+ zfcp_get_busid_by_adapter(adapter));
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ retval = -EINVAL;
+ break;
+
+ case FSF_INVALID_COMMAND_OPTION:
+ ZFCP_LOG_FLAGS(2, "FSF_INVALID_COMMAND_OPTION\n");
+ ZFCP_LOG_NORMAL(
+ "Invalid option 0x%x has been specified "
+ "in QTCB bottom sent to the adapter %s\n",
+ bottom->option,
+ zfcp_get_busid_by_adapter(adapter));
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ retval = -EINVAL;
+ break;
+
+ default:
+ ZFCP_LOG_NORMAL(
+ "bug: An unknown/unexpected FSF status 0x%08x "
+ "was presented on the adapter %s\n",
+ header->fsf_status,
+ zfcp_get_busid_by_adapter(adapter));
+ debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_sq_inval");
+ debug_exception(fsf_req->adapter->erp_dbf, 0,
+ &header->fsf_status_qual.word[0], sizeof(u32));
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ retval = -EINVAL;
+ break;
+ }
+
+skip_fsfstatus:
+ return retval;
+}
+
+
/*
* function: zfcp_fsf_req_wait_and_cleanup
*
return 0;
}
+/*
+ * set qtcb pointer in fsf_req and initialize QTCB
+ */
+static inline void
+zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req, u32 fsf_cmd)
+{
+ if (likely(fsf_req->qtcb != NULL)) {
+ fsf_req->qtcb->prefix.req_id = (unsigned long)fsf_req;
+ fsf_req->qtcb->prefix.ulp_info = ZFCP_ULP_INFO_VERSION;
+ fsf_req->qtcb->prefix.qtcb_type = fsf_qtcb_type[fsf_cmd];
+ fsf_req->qtcb->prefix.qtcb_version = ZFCP_QTCB_VERSION;
+ fsf_req->qtcb->header.req_handle = (unsigned long)fsf_req;
+ fsf_req->qtcb->header.fsf_command = fsf_cmd;
+ }
+}
+
+/**
+ * zfcp_fsf_req_sbal_get - try to get one SBAL in the request queue
+ * @adapter: adapter for which request queue is examined
+ * @req_flags: flags indicating whether to wait for needed SBAL or not
+ * @lock_flags: lock_flags is queue_lock is taken
+ *
+ * locking: on success the queue_lock for the request queue of the adapter
+ * is held
+ */
+static int
+zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter, int req_flags,
+ unsigned long *lock_flags)
+{
+ int condition;
+ unsigned long timeout = ZFCP_SBAL_TIMEOUT;
+ struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
+
+ if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) {
+ ZFCP_WAIT_EVENT_TIMEOUT(adapter->request_wq, timeout,
+ (condition =
+ (zfcp_fsf_req_create_sbal_check)
+ (lock_flags, req_queue, 1)));
+ if (!condition) {
+ return -EIO;
+ }
+ } else if (!zfcp_fsf_req_create_sbal_check(lock_flags, req_queue, 1)) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
/*
* function: zfcp_fsf_req_create
*
* but is held on completion (write, irqsave)
*/
int
-zfcp_fsf_req_create(struct zfcp_adapter *adapter,
- u32 fsf_cmd,
- unsigned long *lock_flags,
- int req_flags,
+zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
+ mempool_t *pool, unsigned long *lock_flags,
struct zfcp_fsf_req **fsf_req_p)
{
+ volatile struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *fsf_req = NULL;
- int retval = 0;
+ int ret = 0;
struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
- volatile struct qdio_buffer_element *buffere;
- unsigned long timeout;
- int condition;
/* allocate new FSF request */
- fsf_req = zfcp_fsf_req_alloc(adapter, fsf_cmd, GFP_ATOMIC);
- if (unlikely(!fsf_req)) {
+ fsf_req = zfcp_fsf_req_alloc(pool, req_flags);
+ if (unlikely(NULL == fsf_req)) {
ZFCP_LOG_DEBUG("error: Could not put an FSF request into"
"the outbound (send) queue.\n");
- retval = -ENOMEM;
+ ret = -ENOMEM;
goto failed_fsf_req;
}
- /* save pointer to "parent" adapter */
- fsf_req->adapter = adapter;
+
+ zfcp_fsf_req_qtcb_init(fsf_req, fsf_cmd);
/* initialize waitqueue which may be used to wait on
this request completion */
init_waitqueue_head(&fsf_req->completion_wq);
+ ret = zfcp_fsf_req_sbal_get(adapter, req_flags, lock_flags);
+ if(ret < 0) {
+ goto failed_sbals;
+ }
+
+
/* set magics */
fsf_req->common_magic = ZFCP_MAGIC;
fsf_req->specific_magic = ZFCP_MAGIC_FSFREQ;
+ fsf_req->adapter = adapter; /* pointer to "parent" adapter */
fsf_req->fsf_command = fsf_cmd;
- if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP))
- fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
+ fsf_req->sbal_number = 1;
+ fsf_req->sbal_first = req_queue->free_index;
+ fsf_req->sbal_curr = req_queue->free_index;
+ fsf_req->sbale_curr = 1;
- /* initialize QTCB */
- if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) {
- ZFCP_LOG_TRACE("fsf_req->qtcb=0x%lx\n",
- (unsigned long) fsf_req->qtcb);
- fsf_req->qtcb->prefix.req_id = (unsigned long) fsf_req;
- fsf_req->qtcb->prefix.ulp_info = ZFCP_ULP_INFO_VERSION;
- fsf_req->qtcb->prefix.qtcb_type = fsf_qtcb_type[fsf_cmd];
- fsf_req->qtcb->prefix.qtcb_version = ZFCP_QTCB_VERSION;
- fsf_req->qtcb->header.req_handle = (unsigned long) fsf_req;
- fsf_req->qtcb->header.fsf_command = fsf_cmd;
- /*
- * Request Sequence Number is set later when the request is
- * actually sent.
- */
+ if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) {
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
}
- /*
- * try to get needed SBALs in request queue (get queue lock on success)
- */
- ZFCP_LOG_TRACE("try to get free BUFFER in request queue\n");
- if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) {
- timeout = ZFCP_SBAL_TIMEOUT;
- ZFCP_WAIT_EVENT_TIMEOUT(adapter->request_wq,
- timeout,
- (condition =
- (zfcp_fsf_req_create_sbal_check)
- (lock_flags, req_queue, 1)));
- if (!condition) {
- retval = -EIO;
- goto failed_sbals;
- }
- } else {
- if (!zfcp_fsf_req_create_sbal_check(lock_flags, req_queue, 1)) {
- retval = -EIO;
- goto failed_sbals;
- }
- }
- fsf_req->sbal_count = 1;
- fsf_req->sbal_index = req_queue->free_index;
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
- ZFCP_LOG_TRACE("got %i free BUFFERs starting at index %i\n",
- fsf_req->sbal_count, fsf_req->sbal_index);
- buffere = req_queue->buffer[fsf_req->sbal_index]->element;
/* setup common SBALE fields */
- buffere[0].addr = fsf_req;
- buffere[0].flags |= SBAL_FLAGS0_COMMAND;
- if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) {
- buffere[1].addr = (void *) fsf_req->qtcb;
- buffere[1].length = ZFCP_QTCB_SIZE;
- }
-
- /* set specific common SBALE and QTCB fields */
- switch (fsf_cmd) {
- case FSF_QTCB_FCP_CMND:
- ZFCP_LOG_FLAGS(3, "FSF_QTCB_FCP_CMND\n");
- /*
- * storage-block type depends on actual
- * SCSI command and is set by calling
- * routine according to transfer direction
- * of data buffers associated with SCSI
- * command
- */
- break;
- case FSF_QTCB_ABORT_FCP_CMND:
- case FSF_QTCB_OPEN_PORT_WITH_DID:
- case FSF_QTCB_OPEN_LUN:
- case FSF_QTCB_CLOSE_LUN:
- case FSF_QTCB_CLOSE_PORT:
- case FSF_QTCB_CLOSE_PHYSICAL_PORT:
- case FSF_QTCB_SEND_ELS: /* FIXME: ELS needs separate case */
- ZFCP_LOG_FLAGS(3, "FSF_QTCB_*\n");
- /*
- * FIXME(qdio):
- * what is the correct type for commands
- * without 'real' data buffers?
- */
- buffere[0].flags |= SBAL_FLAGS0_TYPE_READ;
- buffere[1].flags |= SBAL_FLAGS_LAST_ENTRY;
- break;
- case FSF_QTCB_EXCHANGE_CONFIG_DATA:
- ZFCP_LOG_FLAGS(3, "FSF_QTCB_EXCHANGE_CONFIG_DATA\n");
- buffere[0].flags |= SBAL_FLAGS0_TYPE_READ;
- buffere[1].flags |= SBAL_FLAGS_LAST_ENTRY;
- break;
-
- case FSF_QTCB_SEND_GENERIC:
- ZFCP_LOG_FLAGS(3, "FSF_QTCB_SEND_GENERIC\n");
- buffere[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
- break;
-
- case FSF_QTCB_UNSOLICITED_STATUS:
- ZFCP_LOG_FLAGS(3, "FSF_QTCB_UNSOLICITED_STATUS\n");
- buffere[0].flags |= SBAL_FLAGS0_TYPE_STATUS;
- buffere[2].flags |= SBAL_FLAGS_LAST_ENTRY;
- break;
-
- default:
- ZFCP_LOG_NORMAL("bug: An attempt to send an unsupported "
- "command has been detected. "
- "(debug info 0x%x)\n", fsf_cmd);
- goto unsupported_fsf_cmd;
+ sbale[0].addr = fsf_req;
+ sbale[0].flags |= SBAL_FLAGS0_COMMAND;
+ if (likely(fsf_req->qtcb != NULL)) {
+ sbale[1].addr = (void *) fsf_req->qtcb;
+ sbale[1].length = sizeof(struct fsf_qtcb);
}
- /* yes, we did it - skip all cleanups for different failures */
- goto out;
+ ZFCP_LOG_TRACE("got %i free BUFFERs starting at index %i\n",
+ fsf_req->sbal_number, fsf_req->sbal_first);
- unsupported_fsf_cmd:
+ goto success;
failed_sbals:
#ifdef ZFCP_STAT_QUEUES
failed_fsf_req:
write_lock_irqsave(&req_queue->queue_lock, *lock_flags);
- out:
+ success:
*fsf_req_p = fsf_req;
- return retval;
+ return ret;
}
/*
static int
zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
{
- int retval = 0;
- struct zfcp_adapter *adapter = fsf_req->adapter;
- struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
- volatile struct qdio_buffer_element *buffere;
- int inc_seq_no = 1;
+ struct zfcp_adapter *adapter;
+ struct zfcp_qdio_queue *req_queue;
+ volatile struct qdio_buffer_element *sbale;
int new_distance_from_int;
unsigned long flags;
+ int inc_seq_no = 1;
+ int retval = 0;
+
+ adapter = fsf_req->adapter;
+ req_queue = &adapter->request_queue,
- u8 sbal_index = fsf_req->sbal_index;
/* FIXME(debug): remove it later */
- buffere = &(req_queue->buffer[sbal_index]->element[0]);
- ZFCP_LOG_DEBUG("zeroeth BUFFERE flags=0x%x \n ", buffere->flags);
- buffere = &(req_queue->buffer[sbal_index]->element[1]);
- ZFCP_LOG_TRACE("HEX DUMP OF 0eth BUFFERE PAYLOAD:\n");
- ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) buffere->addr,
- buffere->length);
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_first, 0);
+ ZFCP_LOG_DEBUG("SBALE0 flags=0x%x\n", sbale[0].flags);
+ ZFCP_LOG_TRACE("HEX DUMP OF SBALE1 PAYLOAD:\n");
+ ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) sbale[1].addr,
+ sbale[1].length);
/* set sequence counter in QTCB */
if (likely(fsf_req->qtcb)) {
"index_in_queue=%i, count=%i, buffers=0x%lx\n",
zfcp_get_busid_by_adapter(adapter),
QDIO_FLAG_SYNC_OUTPUT,
- 0,
- sbal_index,
- fsf_req->sbal_count,
- (unsigned long) &req_queue->buffer[sbal_index]);
+ 0, fsf_req->sbal_first, fsf_req->sbal_number,
+ (unsigned long) &req_queue->buffer[fsf_req->sbal_first]);
/*
* adjust the number of free SBALs in request queue as well as
* position of first one
*/
- atomic_sub(fsf_req->sbal_count, &req_queue->free_count);
+ atomic_sub(fsf_req->sbal_number, &req_queue->free_count);
ZFCP_LOG_TRACE("free_count=%d\n", atomic_read(&req_queue->free_count));
- req_queue->free_index += fsf_req->sbal_count; /* increase */
+ req_queue->free_index += fsf_req->sbal_number; /* increase */
req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap if needed */
new_distance_from_int = zfcp_qdio_determine_pci(req_queue, fsf_req);
retval = do_QDIO(adapter->ccw_device,
QDIO_FLAG_SYNC_OUTPUT,
- 0, fsf_req->sbal_index, fsf_req->sbal_count, NULL);
+ 0, fsf_req->sbal_first, fsf_req->sbal_number, NULL);
if (unlikely(retval)) {
/* Queues are down..... */
* position of first one
*/
zfcp_qdio_zero_sbals(req_queue->buffer,
- fsf_req->sbal_index, fsf_req->sbal_count);
- atomic_add(fsf_req->sbal_count, &req_queue->free_count);
- req_queue->free_index -= fsf_req->sbal_count; /* increase */
+ fsf_req->sbal_first, fsf_req->sbal_number);
+ atomic_add(fsf_req->sbal_number, &req_queue->free_count);
+ req_queue->free_index -= fsf_req->sbal_number; /* increase */
req_queue->free_index += QDIO_MAX_BUFFERS_PER_Q;
req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */
ZFCP_LOG_DEBUG
zfcp_fsf_req_free(fsf_req);
}
-/*
- * try to allocate fsf_req with QTCB,
- * alternately try to get hold of fsf_req+QTCB provided by the specified memory
- * pool element, this routine is called for all kinds of fsf requests other than
- * status read since status read does neither require kmalloc involvement
- * nor a QTCB
- */
-static struct zfcp_fsf_req *
-zfcp_fsf_req_get(int kmalloc_flags, mempool_t * pool)
-{
- struct zfcp_fsf_req *fsf_req;
-
- fsf_req = kmalloc(ZFCP_QTCB_AND_REQ_SIZE, kmalloc_flags);
- if (likely(fsf_req)) {
- memset(fsf_req, 0, ZFCP_QTCB_AND_REQ_SIZE);
- } else {
- fsf_req = mempool_alloc(pool, kmalloc_flags);
- if (likely(fsf_req)) {
- memset(fsf_req, 0, ZFCP_QTCB_AND_REQ_SIZE);
- fsf_req->status |= ZFCP_STATUS_FSFREQ_POOL;
- }
- }
- if (likely(fsf_req))
- fsf_req->qtcb =
- (struct fsf_qtcb *) ((unsigned long) fsf_req +
- sizeof (struct zfcp_fsf_req));
-
- return fsf_req;
-}
-
#undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
*
* FCP adapter driver for IBM eServer zSeries
*
- * Copyright 2002 IBM Corporation
+ * (C) Copyright IBM Corp. 2002, 2004
+ *
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com>
- * Aron Zeh <arzeh@de.ibm.com>
- * Wolfgang Taphorn <taphorn@de.ibm.com>
+ * Aron Zeh
+ * Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
#define FSF_QTCB_SEND_ELS 0x0000000B
#define FSF_QTCB_SEND_GENERIC 0x0000000C
#define FSF_QTCB_EXCHANGE_CONFIG_DATA 0x0000000D
+#define FSF_QTCB_EXCHANGE_PORT_DATA 0x0000000E
+#define FSF_QTCB_DOWNLOAD_CONTROL_FILE 0x00000012
+#define FSF_QTCB_UPLOAD_CONTROL_FILE 0x00000013
/* FSF QTCB types */
#define FSF_IO_COMMAND 0x00000001
#define FSF_SUPPORT_COMMAND 0x00000002
#define FSF_CONFIG_COMMAND 0x00000003
+#define FSF_PORT_COMMAND 0x00000004
+
+/* FSF control file upload/download operations' subtype and options */
+#define FSF_CFDC_OPERATION_SUBTYPE 0x00020001
+#define FSF_CFDC_OPTION_NORMAL_MODE 0x00000000
+#define FSF_CFDC_OPTION_FORCE 0x00000001
+#define FSF_CFDC_OPTION_FULL_ACCESS 0x00000002
+#define FSF_CFDC_OPTION_RESTRICTED_ACCESS 0x00000004
/* FSF protocol stati */
#define FSF_PROT_GOOD 0x00000001
#define FSF_HANDLE_MISMATCH 0x00000005
#define FSF_SERVICE_CLASS_NOT_SUPPORTED 0x00000006
#define FSF_FCPLUN_NOT_VALID 0x00000009
-//#define FSF_ACCESS_DENIED 0x00000010
+#define FSF_ACCESS_DENIED 0x00000010
#define FSF_ACCESS_TYPE_NOT_VALID 0x00000011
-#define FSF_LUN_IN_USE 0x00000012
+#define FSF_LUN_SHARING_VIOLATION 0x00000012
#define FSF_COMMAND_ABORTED_ULP 0x00000020
#define FSF_COMMAND_ABORTED_ADAPTER 0x00000021
#define FSF_FCP_COMMAND_DOES_NOT_EXIST 0x00000022
#define FSF_RESPONSE_BUF_NOT_VALID 0x00000043
#define FSF_ELS_COMMAND_REJECTED 0x00000050
#define FSF_GENERIC_COMMAND_REJECTED 0x00000051
-//#define FSF_AUTHORIZATION_FAILURE 0x00000053
+#define FSF_OPERATION_PARTIALLY_SUCCESSFUL 0x00000052
+#define FSF_AUTHORIZATION_FAILURE 0x00000053
+#define FSF_CFDC_ERROR_DETECTED 0x00000054
+#define FSF_CONTROL_FILE_UPDATE_ERROR 0x00000055
+#define FSF_CONTROL_FILE_TOO_LARGE 0x00000056
+#define FSF_ACCESS_CONFLICT_DETECTED 0x00000057
+#define FSF_CONFLICTS_OVERRULED 0x00000058
#define FSF_PORT_BOXED 0x00000059
-//#define FSF_LUN_BOXED 0x0000005A
+#define FSF_LUN_BOXED 0x0000005A
+#define FSF_PAYLOAD_SIZE_MISMATCH 0x00000060
+#define FSF_REQUEST_SIZE_TOO_LARGE 0x00000061
+#define FSF_RESPONSE_SIZE_TOO_LARGE 0x00000062
#define FSF_ADAPTER_STATUS_AVAILABLE 0x000000AD
#define FSF_FCP_RSP_AVAILABLE 0x000000AF
#define FSF_UNKNOWN_COMMAND 0x000000E2
-//#define FSF_ERROR 0x000000FF
+#define FSF_UNKNOWN_OP_SUBTYPE 0x000000E3
+#define FSF_INVALID_COMMAND_OPTION 0x000000E5
+/* #define FSF_ERROR 0x000000FF */
#define FSF_STATUS_QUALIFIER_SIZE 16
#define FSF_SQ_COMMAND_ABORTED 0x06
#define FSF_SQ_NO_RETRY_POSSIBLE 0x07
+/* FSF status qualifier for CFDC commands */
+#define FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE 0x00000001
+#define FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2 0x00000002
+/* CFDC subtable codes */
+#define FSF_SQ_CFDC_SUBTABLE_OS 0x0001
+#define FSF_SQ_CFDC_SUBTABLE_PORT_WWPN 0x0002
+#define FSF_SQ_CFDC_SUBTABLE_PORT_DID 0x0003
+#define FSF_SQ_CFDC_SUBTABLE_LUN 0x0004
+
/* FSF status qualifier (most significant 4 bytes), local link down */
#define FSF_PSQ_LINK_NOLIGHT 0x00000004
#define FSF_PSQ_LINK_WRAPPLUG 0x00000008
#define FSF_STATUS_READ_BIT_ERROR_THRESHOLD 0x00000004
#define FSF_STATUS_READ_LINK_DOWN 0x00000005 /* FIXME: really? */
#define FSF_STATUS_READ_LINK_UP 0x00000006
+#define FSF_STATUS_READ_NOTIFICATION_LOST 0x00000009
+#define FSF_STATUS_READ_CFDC_UPDATED 0x0000000A
+#define FSF_STATUS_READ_CFDC_HARDENED 0x0000000B
/* status subtypes in status read buffer */
#define FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT 0x00000001
#define FSF_STATUS_READ_SUB_ERROR_PORT 0x00000002
+/* status subtypes for CFDC */
+#define FSF_STATUS_READ_SUB_LOST_CFDC_UPDATED 0x00000020
+#define FSF_STATUS_READ_SUB_LOST_CFDC_HARDENED 0x00000040
+#define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE 0x00000002
+#define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2 0x0000000F
+
/* topologie that is detected by the adapter */
#define FSF_TOPO_ERROR 0x00000000
#define FSF_TOPO_P2P 0x00000001
/* SBAL chaining */
#define FSF_MAX_SBALS_PER_REQ 36
+#define FSF_MAX_SBALS_PER_ELS_REQ 2
/* logging space behind QTCB */
#define FSF_QTCB_LOG_SIZE 1024
+/* channel features */
+#define FSF_FEATURE_QTCB_SUPPRESSION 0x00000001
+#define FSF_FEATURE_CFDC 0x00000002
+#define FSF_FEATURE_SENSEDATA_REPLICATION 0x00000004
+#define FSF_FEATURE_LOST_SAN_NOTIFICATION 0x00000008
+#define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010
+#define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020
+
+/* option */
+#define FSF_OPEN_LUN_SUPPRESS_BOXING 0x00000001
+
+/* adapter types */
+#define FSF_ADAPTER_TYPE_FICON 0x00000001
+#define FSF_ADAPTER_TYPE_FICON_EXPRESS 0x00000002
+
+/* port types */
+#define FSF_HBA_PORTTYPE_UNKNOWN 0x00000001
+#define FSF_HBA_PORTTYPE_NOTPRESENT 0x00000003
+#define FSF_HBA_PORTTYPE_NPORT 0x00000005
+#define FSF_HBA_PORTTYPE_PTP 0x00000021
+/* following are not defined and used by FSF Spec
+ but are additionally defined by FC-HBA */
+#define FSF_HBA_PORTTYPE_OTHER 0x00000002
+#define FSF_HBA_PORTTYPE_NOTPRESENT 0x00000003
+#define FSF_HBA_PORTTYPE_NLPORT 0x00000006
+#define FSF_HBA_PORTTYPE_FLPORT 0x00000007
+#define FSF_HBA_PORTTYPE_FPORT 0x00000008
+#define FSF_HBA_PORTTYPE_LPORT 0x00000020
+
+/* port states */
+#define FSF_HBA_PORTSTATE_UNKNOWN 0x00000001
+#define FSF_HBA_PORTSTATE_ONLINE 0x00000002
+#define FSF_HBA_PORTSTATE_OFFLINE 0x00000003
+#define FSF_HBA_PORTSTATE_LINKDOWN 0x00000006
+#define FSF_HBA_PORTSTATE_ERROR 0x00000007
+
+
struct fsf_queue_designator;
struct fsf_status_read_buffer;
struct fsf_port_closed_payload;
} __attribute__ ((packed));
struct fsf_qtcb_bottom_support {
- u8 res1[16];
+ u32 operation_subtype;
+ u8 res1[12];
u32 d_id;
- u32 res2;
+ u32 option;
u64 fcp_lun;
- u64 res3;
+ u64 res2;
u64 req_handle;
u32 service_class;
- u8 res4[3];
+ u8 res3[3];
u8 timeout;
- u8 res5[184];
+ u8 res4[184];
u32 els1_length;
u32 els2_length;
- u64 res6;
+ u32 req_buf_length;
+ u32 resp_buf_length;
u8 els[256];
} __attribute__ ((packed));
struct fsf_qtcb_bottom_config {
u32 lic_version;
- u32 res1;
+ u32 feature_selection;
u32 high_qtcb_version;
u32 low_qtcb_version;
u32 max_qtcb_size;
- u8 res2[12];
+ u32 max_data_transfer_size;
+ u32 supported_features;
+ u8 res1[4];
u32 fc_topology;
u32 fc_link_speed;
u32 adapter_type;
u32 peer_d_id;
- u8 res3[12];
+ u8 res2[12];
u32 s_id;
struct fsf_nport_serv_param nport_serv_param;
- u8 res4[320];
+ u8 res3[8];
+ u32 adapter_ports;
+ u32 hardware_version;
+ u8 serial_number[32];
+ u8 res4[272];
+} __attribute__ ((packed));
+
+struct fsf_qtcb_bottom_port {
+ u8 res1[8];
+ u32 fc_port_id;
+ u32 port_type;
+ u32 port_state;
+ u32 class_of_service; /* should be 0x00000006 for class 2 and 3 */
+ u8 supported_fc4_types[32]; /* should be 0x00000100 for scsi fcp */
+ u8 active_fc4_types[32];
+ u32 supported_speed; /* 0x0001 for 1 GBit/s or 0x0002 for 2 GBit/s */
+ u32 maximum_frame_size; /* fixed value of 2112 */
+ u64 seconds_since_last_reset;
+ u64 tx_frames;
+ u64 tx_words;
+ u64 rx_frames;
+ u64 rx_words;
+ u64 lip; /* 0 */
+ u64 nos; /* currently 0 */
+ u64 error_frames; /* currently 0 */
+ u64 dumped_frames; /* currently 0 */
+ u64 link_failure;
+ u64 loss_of_sync;
+ u64 loss_of_signal;
+ u64 psp_error_counts;
+ u64 invalid_tx_words;
+ u64 invalid_crcs;
+ u64 input_requests;
+ u64 output_requests;
+ u64 control_requests;
+ u64 input_mb; /* where 1 MByte == 1.000.000 Bytes */
+ u64 output_mb; /* where 1 MByte == 1.000.000 Bytes */
+ u8 res2[256];
} __attribute__ ((packed));
union fsf_qtcb_bottom {
struct fsf_qtcb_bottom_io io;
struct fsf_qtcb_bottom_support support;
struct fsf_qtcb_bottom_config config;
+ struct fsf_qtcb_bottom_port port;
};
struct fsf_qtcb {
struct fsf_qtcb_prefix prefix;
struct fsf_qtcb_header header;
union fsf_qtcb_bottom bottom;
+ u8 log[FSF_QTCB_LOG_SIZE];
} __attribute__ ((packed));
#endif /* FSF_H */
*
* QDIO related routines
*
- * Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
+ * (C) Copyright IBM Corp. 2002, 2004
+ *
* Authors:
* Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com>
- * Wolfgang Taphorn <taphorn@de.ibm.com>
+ * Wolfgang Taphorn
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#define ZFCP_QDIO_C_REVISION "$Revision: 1.10 $"
+#define ZFCP_QDIO_C_REVISION "$Revision: 1.13 $"
#include "zfcp_ext.h"
+static inline void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int);
+static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_get
+ (struct zfcp_qdio_queue *, int, int);
+static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_resp
+ (struct zfcp_fsf_req *, int, int);
+static inline volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain
+ (struct zfcp_fsf_req *, unsigned long);
+static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_next
+ (struct zfcp_fsf_req *, unsigned long);
+static inline int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int);
+static inline int zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *);
+static inline void zfcp_qdio_sbale_fill
+ (struct zfcp_fsf_req *, unsigned long, void *, int);
+static inline int zfcp_qdio_sbals_from_segment
+ (struct zfcp_fsf_req *, unsigned long, void *, unsigned long);
+static inline int zfcp_qdio_sbals_from_buffer
+ (struct zfcp_fsf_req *, unsigned long, void *, unsigned long, int);
+
static qdio_handler_t zfcp_qdio_request_handler;
static qdio_handler_t zfcp_qdio_response_handler;
static int zfcp_qdio_handler_error_check(struct zfcp_adapter *,
unsigned int, unsigned int);
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_QDIO
-#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_QDIO
/*
* Allocates BUFFER memory to each of the pointers of the qdio_buffer_t
atomic_add(elements_processed, &queue->free_count);
ZFCP_LOG_DEBUG("free_count=%d\n", atomic_read(&queue->free_count));
wake_up(&adapter->request_wq);
- ZFCP_LOG_DEBUG("Elements_processed = %d, free count=%d \n",
+ ZFCP_LOG_DEBUG("Elements_processed = %d, free count=%d\n",
elements_processed, atomic_read(&queue->free_count));
out:
return;
*/
buffere = &(queue->buffer[first_element]->element[0]);
- ZFCP_LOG_DEBUG("first BUFFERE flags=0x%x \n ", buffere->flags);
+ ZFCP_LOG_DEBUG("first BUFFERE flags=0x%x \n", buffere->flags);
/*
* go through all SBALs from input queue currently
* returned by QDIO layer
(unsigned long) fsf_req, (unsigned long) fsf_req->qtcb);
if (likely(fsf_req->qtcb)) {
ZFCP_LOG_TRACE("HEX DUMP OF 1ST BUFFERE PAYLOAD (QTCB):\n");
- ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
- (char *) fsf_req->qtcb, ZFCP_QTCB_SIZE);
+ ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) fsf_req->qtcb,
+ sizeof(struct fsf_qtcb));
}
/* finish the FSF request */
return retval;
}
+/**
+ * zfcp_qdio_sbale_get - return pointer to SBALE of qdio_queue
+ * @queue: queue from which SBALE should be returned
+ * @sbal: specifies number of SBAL in queue
+ * @sbale: specifes number of SBALE in SBAL
+ */
+static inline volatile struct qdio_buffer_element *
+zfcp_qdio_sbale_get(struct zfcp_qdio_queue *queue, int sbal, int sbale)
+{
+ return &queue->buffer[sbal]->element[sbale];
+}
+
+/**
+ * zfcp_qdio_sbale_req - return pointer to SBALE of request_queue for
+ * a struct zfcp_fsf_req
+ */
+inline volatile struct qdio_buffer_element *
+zfcp_qdio_sbale_req(struct zfcp_fsf_req *fsf_req, int sbal, int sbale)
+{
+ return zfcp_qdio_sbale_get(&fsf_req->adapter->request_queue,
+ sbal, sbale);
+}
+
+/**
+ * zfcp_qdio_sbale_resp - return pointer to SBALE of response_queue for
+ * a struct zfcp_fsf_req
+ */
+static inline volatile struct qdio_buffer_element *
+zfcp_qdio_sbale_resp(struct zfcp_fsf_req *fsf_req, int sbal, int sbale)
+{
+ return zfcp_qdio_sbale_get(&fsf_req->adapter->response_queue,
+ sbal, sbale);
+}
+
+/**
+ * zfcp_qdio_sbale_curr - return current SBALE on request_queue for
+ * a struct zfcp_fsf_req
+ */
+inline volatile struct qdio_buffer_element *
+zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req)
+{
+ return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr,
+ fsf_req->sbale_curr);
+}
+
+/**
+ * zfcp_qdio_sbal_limit - determine maximum number of SBALs that can be used
+ * on the request_queue for a struct zfcp_fsf_req
+ * @fsf_req: the number of the last SBAL that can be used is stored herein
+ * @max_sbals: used to pass an upper limit for the number of SBALs
+ *
+ * Note: We can assume at least one free SBAL in the request_queue when called.
+ */
+static inline void
+zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals)
+{
+ int count = atomic_read(&fsf_req->adapter->request_queue.free_count);
+ count = min(count, max_sbals);
+ fsf_req->sbal_last = fsf_req->sbal_first;
+ fsf_req->sbal_last += (count - 1);
+ fsf_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q;
+}
+
+/**
+ * zfcp_qdio_sbal_chain - chain SBALs if more than one SBAL is needed for a
+ * request
+ * @fsf_req: zfcp_fsf_req to be processed
+ * @sbtype: SBAL flags which have to be set in first SBALE of new SBAL
+ *
+ * This function changes sbal_curr, sbale_curr, sbal_number of fsf_req.
+ */
+static inline volatile struct qdio_buffer_element *
+zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
+{
+ volatile struct qdio_buffer_element *sbale;
+
+ /* set last entry flag in current SBALE of current SBAL */
+ sbale = zfcp_qdio_sbale_curr(fsf_req);
+ sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
+
+ /* don't exceed last allowed SBAL */
+ if (fsf_req->sbal_curr == fsf_req->sbal_last)
+ return NULL;
+
+ /* set chaining flag in first SBALE of current SBAL */
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale->flags |= SBAL_FLAGS0_MORE_SBALS;
+
+ /* calculate index of next SBAL */
+ fsf_req->sbal_curr++;
+ fsf_req->sbal_curr %= QDIO_MAX_BUFFERS_PER_Q;
+
+ /* keep this requests number of SBALs up-to-date */
+ fsf_req->sbal_number++;
+
+ /* start at first SBALE of new SBAL */
+ fsf_req->sbale_curr = 0;
+
+ /* set storage-block type for new SBAL */
+ sbale = zfcp_qdio_sbale_curr(fsf_req);
+ sbale->flags |= sbtype;
+
+ return sbale;
+}
+
+/**
+ * zfcp_qdio_sbale_next - switch to next SBALE, chain SBALs if needed
+ */
+static inline volatile struct qdio_buffer_element *
+zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
+{
+ if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
+ return zfcp_qdio_sbal_chain(fsf_req, sbtype);
+
+ fsf_req->sbale_curr++;
+
+ return zfcp_qdio_sbale_curr(fsf_req);
+}
+
+/**
+ * zfcp_qdio_sbals_zero - initialize SBALs between first and last in queue
+ * with zero from
+ */
+static inline int
+zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *queue, int first, int last)
+{
+ struct qdio_buffer **buf = queue->buffer;
+ int curr = first;
+ int count = 0;
+
+ for(;;) {
+ curr %= QDIO_MAX_BUFFERS_PER_Q;
+ count++;
+ memset(buf[curr], 0, sizeof(struct qdio_buffer));
+ if (curr == last)
+ break;
+ curr++;
+ }
+ return count;
+}
+
+
+/**
+ * zfcp_qdio_sbals_wipe - reset all changes in SBALs for an fsf_req
+ */
+static inline int
+zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req)
+{
+ return zfcp_qdio_sbals_zero(&fsf_req->adapter->request_queue,
+ fsf_req->sbal_first, fsf_req->sbal_curr);
+}
+
+
+/**
+ * zfcp_qdio_sbale_fill - set address and lenght in current SBALE
+ * on request_queue
+ */
+static inline void
+zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
+ void *addr, int length)
+{
+ volatile struct qdio_buffer_element *sbale;
+
+ sbale = zfcp_qdio_sbale_curr(fsf_req);
+ sbale->addr = addr;
+ sbale->length = length;
+
+#ifdef ZFCP_STAT_REQSIZES
+ if (sbtype == SBAL_FLAGS0_TYPE_READ)
+ zfcp_statistics_inc(&zfcp_data.read_sg_head, length);
+ else zfcp_statistics_inc(&zfcp_data.write_sg_head, length);
+#endif
+}
+
+/**
+ * zfcp_qdio_sbals_from_segment - map memory segment to SBALE(s)
+ * @fsf_req: request to be processed
+ * @sbtype: SBALE flags
+ * @start_addr: address of memory segment
+ * @total_length: length of memory segment
+ *
+ * Alignment and length of the segment determine how many SBALEs are needed
+ * for the memory segment.
+ */
+static inline int
+zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
+ void *start_addr, unsigned long total_length)
+{
+ unsigned long remaining, length;
+ void *addr;
+
+ /* split segment up heeding page boundaries */
+ for (addr = start_addr, remaining = total_length; remaining > 0;
+ addr += length, remaining -= length) {
+ /* get next free SBALE for new piece */
+ if (NULL == zfcp_qdio_sbale_next(fsf_req, sbtype)) {
+ /* no SBALE left, clean up and leave */
+ zfcp_qdio_sbals_wipe(fsf_req);
+ return -EINVAL;
+ }
+ /* calculate length of new piece */
+ length = min(remaining,
+ (PAGE_SIZE - ((unsigned long) addr &
+ (PAGE_SIZE - 1))));
+ /* fill current SBALE with calculated piece */
+ zfcp_qdio_sbale_fill(fsf_req, sbtype, addr, length);
+ }
+ return total_length;
+}
+
+
+/**
+ * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list
+ * @fsf_req: request to be processed
+ * @sbtype: SBALE flags
+ * @sg: scatter-gather list
+ * @sg_count: number of elements in scatter-gather list
+ * @max_sbals: upper bound for number of SBALs to be used
+ */
+inline int
+zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
+ struct scatterlist *sg, int sg_count, int max_sbals)
+{
+ int sg_index;
+ struct scatterlist *sg_segment;
+ int retval;
+ volatile struct qdio_buffer_element *sbale;
+ int bytes = 0;
+
+ /* figure out last allowed SBAL */
+ zfcp_qdio_sbal_limit(fsf_req, max_sbals);
+
+ /* set storage-block type for current SBAL */
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale->flags |= sbtype;
+
+ /* process all segements of scatter-gather list */
+ for (sg_index = 0, sg_segment = sg, bytes = 0;
+ sg_index < sg_count;
+ sg_index++, sg_segment++) {
+ retval = zfcp_qdio_sbals_from_segment(
+ fsf_req,
+ sbtype,
+ zfcp_sg_to_address(sg_segment),
+ sg_segment->length);
+ if (retval < 0) {
+ bytes = retval;
+ goto out;
+ } else
+ bytes += retval;
+ }
+ /* assume that no other SBALEs are to follow in the same SBAL */
+ sbale = zfcp_qdio_sbale_curr(fsf_req);
+ sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
+
+out:
+#ifdef ZFCP_STAT_REQSIZES
+ if (sbtype == SBAL_FLAGS0_TYPE_READ) {
+ zfcp_statistics_inc(&zfcp_data.read_sguse_head, sg_count);
+ zfcp_statistics_inc(&zfcp_data.read_req_head, bytes);
+ } else {
+ zfcp_statistics_inc(&zfcp_data.write_sguse_head, sg_count);
+ zfcp_statistics_inc(&zfcp_data.write_req_head, bytes);
+ }
+#endif
+
+ return bytes;
+}
+
+
+/**
+ * zfcp_qdio_sbals_from_buffer - fill SBALs from buffer
+ * @fsf_req: request to be processed
+ * @sbtype: SBALE flags
+ * @buffer: data buffer
+ * @length: length of buffer
+ * @max_sbals: upper bound for number of SBALs to be used
+ */
+static inline int
+zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
+ void *buffer, unsigned long length, int max_sbals)
+{
+ struct scatterlist sg_segment;
+
+ zfcp_address_to_sg(buffer, &sg_segment);
+ sg_segment.length = length;
+
+ return zfcp_qdio_sbals_from_sg(fsf_req, sbtype, &sg_segment, 1,
+ max_sbals);
+}
+
+
+/**
+ * zfcp_qdio_sbals_from_scsicmnd - fill SBALs from scsi command
+ * @fsf_req: request to be processed
+ * @sbtype: SBALE flags
+ * @scsi_cmnd: either scatter-gather list or buffer contained herein is used
+ * to fill SBALs
+ */
+inline int
+zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req,
+ unsigned long sbtype, struct scsi_cmnd *scsi_cmnd)
+{
+ if (scsi_cmnd->use_sg) {
+ return zfcp_qdio_sbals_from_sg(fsf_req, sbtype,
+ (struct scatterlist *)
+ scsi_cmnd->request_buffer,
+ scsi_cmnd->use_sg,
+ ZFCP_MAX_SBALS_PER_REQ);
+ } else {
+ return zfcp_qdio_sbals_from_buffer(fsf_req, sbtype,
+ scsi_cmnd->request_buffer,
+ scsi_cmnd->request_bufflen,
+ ZFCP_MAX_SBALS_PER_REQ);
+ }
+}
+
+/**
+ * zfcp_qdio_determine_pci - set PCI flag in first SBALE on qdio queue if needed
+ */
int
zfcp_qdio_determine_pci(struct zfcp_qdio_queue *req_queue,
struct zfcp_fsf_req *fsf_req)
{
int new_distance_from_int;
int pci_pos;
+ volatile struct qdio_buffer_element *sbale;
new_distance_from_int = req_queue->distance_from_int +
- fsf_req->sbal_count;
+ fsf_req->sbal_number;
+
if (unlikely(new_distance_from_int >= ZFCP_QDIO_PCI_INTERVAL)) {
new_distance_from_int %= ZFCP_QDIO_PCI_INTERVAL;
- pci_pos = fsf_req->sbal_index;
- pci_pos += fsf_req->sbal_count;
+ pci_pos = fsf_req->sbal_first;
+ pci_pos += fsf_req->sbal_number;
pci_pos -= new_distance_from_int;
pci_pos -= 1;
pci_pos %= QDIO_MAX_BUFFERS_PER_Q;
- req_queue->buffer[pci_pos]->element[0].flags |= SBAL_FLAGS0_PCI;
- ZFCP_LOG_TRACE("Setting PCI flag at pos %d\n", pci_pos);
+ sbale = zfcp_qdio_sbale_req(fsf_req, pci_pos, 0);
+ sbale->flags |= SBAL_FLAGS0_PCI;
}
return new_distance_from_int;
}
}
#undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
*
* FCP adapter driver for IBM eServer zSeries
*
- * Copyright 2002 IBM Corporation
+ * (C) Copyright IBM Corp. 2002, 2004
+ *
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com>
- * Aron Zeh <arzeh@de.ibm.com>
- * Wolfgang Taphorn <taphorn@de.ibm.com>
+ * Aron Zeh
+ * Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
*/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI
-#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_SCSI
+
/* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_SCSI_REVISION "$Revision: 1.42 $"
+#define ZFCP_SCSI_REVISION "$Revision: 1.52 $"
#include <linux/blkdev.h>
static void zfcp_scsi_slave_destroy(struct scsi_device *sdp);
static int zfcp_scsi_slave_alloc(struct scsi_device *sdp);
static int zfcp_scsi_slave_configure(struct scsi_device *sdp);
-static int zfcp_scsi_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-static int zfcp_scsi_eh_abort_handler(Scsi_Cmnd *);
-static int zfcp_scsi_eh_device_reset_handler(Scsi_Cmnd *);
-static int zfcp_scsi_eh_bus_reset_handler(Scsi_Cmnd *);
-static int zfcp_scsi_eh_host_reset_handler(Scsi_Cmnd *);
+static int zfcp_scsi_queuecommand(struct scsi_cmnd *,
+ void (*done) (struct scsi_cmnd *));
+static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *);
+static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *);
+static int zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *);
+static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *);
static int zfcp_task_management_function(struct zfcp_unit *, u8);
-static int zfcp_create_sbales_from_segment(unsigned long, int, int *,
- int, int, int *, int *, int,
- int, struct qdio_buffer **,
- char);
-
-static int zfcp_create_sbale(unsigned long, int, int *, int, int, int *,
- int, int, int *, struct qdio_buffer **,
- char);
-
-static struct zfcp_unit *zfcp_scsi_determine_unit(struct zfcp_adapter *,
- Scsi_Cmnd *);
static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, int, int);
static struct device_attribute *zfcp_sysfs_sdev_attrs[];
}
}
-void
-zfcp_scsi_block_requests(struct Scsi_Host *shpnt)
-{
- scsi_block_requests(shpnt);
- /* This is still somewhat racy but the best I could imagine */
- do {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(ZFCP_SCSI_HOST_FLUSH_TIMEOUT);
-
- } while (shpnt->host_busy || shpnt->eh_active);
-}
-
/*
- * Tries to associate a zfcp unit with the scsi device.
- *
- * returns: unit pointer if unit is found
- * NULL otherwise
- */
-struct zfcp_unit *
-zfcp_scsi_determine_unit(struct zfcp_adapter *adapter, Scsi_Cmnd * scpnt)
-{
- struct zfcp_unit *unit;
-
- /*
- * figure out target device
- * (stored there by zfcp_scsi_slave_alloc)
- * ATTENTION: assumes hostdata initialized to NULL by
- * mid layer (see scsi_scan.c)
- */
- unit = (struct zfcp_unit *) scpnt->device->hostdata;
- if (!unit) {
- ZFCP_LOG_DEBUG("logical unit (%i %i %i %i) not configured\n",
- scpnt->device->host->host_no,
- scpnt->device->channel,
- scpnt->device->id, scpnt->device->lun);
- /*
- * must fake SCSI command execution and scsi_done
- * callback for non-configured logical unit
- */
- /* return this as long as we are unable to process requests */
- set_host_byte(&scpnt->result, DID_NO_CONNECT);
- zfcp_cmd_dbf_event_scsi("notconf", scpnt);
- scpnt->scsi_done(scpnt);
-#ifdef ZFCP_DEBUG_REQUESTS
- debug_text_event(adapter->req_dbf, 2, "nc_done:");
- debug_event(adapter->req_dbf, 2, &scpnt,
- sizeof (unsigned long));
-#endif /* ZFCP_DEBUG_REQUESTS */
- }
- return unit;
-}
-
-/*
* called from scsi midlayer to allow finetuning of a device.
*/
static int
return 0;
}
-/* Complete a command immediately handing back DID_ERROR */
+/**
+ * zfcp_scsi_command_fail - set result in scsi_cmnd and call scsi_done function
+ * @scpnt: pointer to struct scsi_cmnd where result is set
+ * @result: result to be set in scpnt (e.g. DID_ERROR)
+ */
static void
-zfcp_scsi_queuecommand_stop(Scsi_Cmnd * scpnt,
- struct zfcp_adapter *adapter,
- struct zfcp_unit *unit)
+zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result)
{
- /* Always pass through to upper layer */
- scpnt->retries = scpnt->allowed - 1;
- set_host_byte(&scpnt->result, DID_ERROR);
- zfcp_cmd_dbf_event_scsi("stopping", scpnt);
+ set_host_byte(&scpnt->result, result);
+ zfcp_cmd_dbf_event_scsi("failing", scpnt);
/* return directly */
scpnt->scsi_done(scpnt);
- if (adapter && unit) {
- ZFCP_LOG_INFO("Stopping SCSI IO on the unit with FCP LUN 0x%Lx "
- "connected to the port with WWPN 0x%Lx at the "
- "adapter %s.\n",
- unit->fcp_lun,
- unit->port->wwpn,
- zfcp_get_busid_by_adapter(adapter));
-#ifdef ZFCP_DEBUG_REQUESTS
- debug_text_event(adapter->req_dbf, 2, "de_done:");
- debug_event(adapter->req_dbf, 2, &scpnt,
- sizeof (unsigned long));
-#endif /* ZFCP_DEBUG_REQUESTS */
- } else {
- ZFCP_LOG_INFO("There is no adapter registered in the zfcp "
- "module for the SCSI host with hostnumber %d. "
- "Stopping IO.\n", scpnt->device->host->host_no);
- }
}
-/*
- * function: zfcp_scsi_queuecommand
- *
- * purpose: enqueues a SCSI command to the specified target device
- *
- * note: The scsi_done midlayer function may be called directly from
- * within queuecommand provided queuecommand returns with
- * success (0).
- * If it fails, it is expected that the command could not be sent
- * and is still available for processing.
- * As we ensure that queuecommand never fails, we have the choice
- * to call done directly wherever we please.
- * Thus, any kind of send errors other than those indicating
- * 'infinite' retries will be reported directly.
- * Retry requests are put into a list to be processed under timer
- * control once in a while to allow for other operations to
- * complete in the meantime.
+/**
+ * zfcp_scsi_command_async - worker for zfcp_scsi_queuecommand and
+ * zfcp_scsi_command_sync
+ * @adapter: adapter for where scsi command is issued
+ * @unit: unit to which scsi command is sent
+ * @scpnt: scsi command to be sent
*
- * returns: 0 - success, SCSI command enqueued
- * !0 - failure, note that we never allow this to happen as the
- * SCSI stack would block indefinitely should a non-zero return
- * value be reported if there are no outstanding commands
- * (as in when the queues are down)
+ * Note: In scsi_done function must be set in scpnt.
*/
int
-zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt, void (*done) (Scsi_Cmnd *))
+zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit,
+ struct scsi_cmnd *scpnt)
{
+ int tmp;
int retval;
- int temp_ret;
- struct zfcp_unit *unit;
- struct zfcp_adapter *adapter;
retval = 0;
- /* reset the status for this request */
- scpnt->result = 0;
- /* save address of mid layer call back function */
- scpnt->scsi_done = done;
- /*
- * figure out adapter
- * (previously stored there by the driver when
- * the adapter was registered)
- */
- adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
- /* NULL when the adapter was removed from the zfcp list */
- if (unlikely(adapter == NULL)) {
- zfcp_scsi_queuecommand_stop(scpnt, NULL, NULL);
- goto out;
- }
- unit = zfcp_scsi_determine_unit(adapter, scpnt);
- if (unlikely(unit == NULL))
+ BUG_ON((adapter == NULL) || (adapter != unit->port->adapter));
+ BUG_ON(scpnt->scsi_done == NULL);
+
+ if (unlikely(NULL == unit)) {
+ zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT);
goto out;
+ }
if (unlikely(
atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status) ||
!atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status))) {
- zfcp_scsi_queuecommand_stop(scpnt, adapter, unit);
+ ZFCP_LOG_DEBUG("Stopping SCSI IO on the unit with "
+ "FCP LUN 0x%Lx connected to the port "
+ "with WWPN 0x%Lx at the adapter %s.\n",
+ unit->fcp_lun,
+ unit->port->wwpn,
+ zfcp_get_busid_by_adapter(adapter));
+ zfcp_scsi_command_fail(scpnt, DID_ERROR);
goto out;
}
+
if (unlikely(
!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))) {
ZFCP_LOG_DEBUG("adapter %s not ready or unit with LUN 0x%Lx "
"on the port with WWPN 0x%Lx in recovery.\n",
- zfcp_get_busid_by_adapter(adapter),
+ zfcp_get_busid_by_unit(unit),
unit->fcp_lun, unit->port->wwpn);
retval = SCSI_MLQUEUE_DEVICE_BUSY;
goto out;
}
- temp_ret = zfcp_fsf_send_fcp_command_task(adapter,
- unit,
- scpnt, ZFCP_REQ_AUTO_CLEANUP);
+ tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt,
+ ZFCP_REQ_AUTO_CLEANUP);
- if (unlikely(temp_ret < 0)) {
+ if (unlikely(tmp < 0)) {
ZFCP_LOG_DEBUG("error: Could not send a Send FCP Command\n");
retval = SCSI_MLQUEUE_HOST_BUSY;
} else {
+
#ifdef ZFCP_DEBUG_REQUESTS
debug_text_event(adapter->req_dbf, 3, "q_scpnt");
debug_event(adapter->req_dbf, 3, &scpnt,
sizeof (unsigned long));
#endif /* ZFCP_DEBUG_REQUESTS */
}
- out:
+
+out:
return retval;
}
+void
+zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt)
+{
+ struct completion *wait = (struct completion *) scpnt->SCp.ptr;
+ complete(wait);
+}
+
+
+/**
+ * zfcp_scsi_command_sync - send a SCSI command and wait for completion
+ * returns 0, errors are indicated by scsi_cmnd->result
+ */
+int
+zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt)
+{
+ DECLARE_COMPLETION(wait);
+
+ scpnt->SCp.ptr = (void *) &wait; /* silent re-use */
+ scpnt->done = zfcp_scsi_command_sync_handler;
+ zfcp_scsi_command_async(unit->port->adapter, unit, scpnt);
+ wait_for_completion(&wait);
+
+ return 0;
+}
+
+/*
+ * function: zfcp_scsi_queuecommand
+ *
+ * purpose: enqueues a SCSI command to the specified target device
+ *
+ * returns: 0 - success, SCSI command enqueued
+ * !0 - failure
+ */
+int
+zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
+ void (*done) (struct scsi_cmnd *))
+{
+ struct zfcp_unit *unit;
+ struct zfcp_adapter *adapter;
+
+ /* reset the status for this request */
+ scpnt->result = 0;
+ /* save address of mid layer call back function */
+ scpnt->scsi_done = done;
+
+ /*
+ * figure out adapter and target device
+ * (stored there by zfcp_scsi_slave_alloc)
+ */
+ adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
+ unit = (struct zfcp_unit *) scpnt->device->hostdata;
+
+ return zfcp_scsi_command_async(adapter, unit, scpnt);
+}
+
/*
* function: zfcp_unit_lookup
*
* FAILED - otherwise
*/
int
-zfcp_scsi_eh_abort_handler(Scsi_Cmnd * scpnt)
+zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
{
int retval = SUCCESS;
struct zfcp_fsf_req *new_fsf_req, *old_fsf_req;
- struct zfcp_adapter *adapter;
- struct zfcp_unit *unit;
- struct zfcp_port *port;
- struct Scsi_Host *scsi_host;
+ struct zfcp_adapter *adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
+ struct zfcp_unit *unit = (struct zfcp_unit *) scpnt->device->hostdata;
+ struct zfcp_port *port = unit->port;
+ struct Scsi_Host *scsi_host = scpnt->device->host;
union zfcp_req_data *req_data = NULL;
unsigned long flags;
u32 status = 0;
- adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
- scsi_host = scpnt->device->host;
- unit = (struct zfcp_unit *) scpnt->device->hostdata;
- port = unit->port;
#ifdef ZFCP_DEBUG_ABORTS
/* the components of a abort_dbf record (fixed size record) */
* returns:
*/
int
-zfcp_scsi_eh_device_reset_handler(Scsi_Cmnd * scpnt)
+zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
{
int retval;
struct zfcp_unit *unit = (struct zfcp_unit *) scpnt->device->hostdata;
* returns:
*/
int
-zfcp_scsi_eh_bus_reset_handler(Scsi_Cmnd * scpnt)
+zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *scpnt)
{
int retval = 0;
struct zfcp_unit *unit;
* returns:
*/
int
-zfcp_scsi_eh_host_reset_handler(Scsi_Cmnd * scpnt)
+zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
{
int retval = 0;
struct zfcp_unit *unit;
}
-/**
- * zfcp_create_sbales_from_segment - creates SBALEs
- * @addr: begin of this buffer segment
- * @length_seg: length of this buffer segment
- * @length_total: total length of buffer
- * @length_min: roll back if generated buffer smaller than this
- * @length_max: sum of all SBALEs (count) not larger than this
- * @buffer_index: position of current BUFFER
- * @buffere_index: position of current BUFFERE
- * @buffer_first: first BUFFER used for this buffer
- * @buffer_last: last BUFFER in request queue allowed
- * @buffer: begin of SBAL array of request queue
- * @sbtype: storage-block type
- */
-static int
-zfcp_create_sbales_from_segment(unsigned long addr, int length_seg,
- int *length_total, int length_min,
- int length_max, int *buffer_index,
- int *buffere_index, int buffer_first,
- int buffer_last, struct qdio_buffer *buffer[],
- char sbtype)
-{
- int retval = 0;
- int length = 0;
-
- ZFCP_LOG_TRACE
- ("SCSI data buffer segment with %i bytes from 0x%lx to 0x%lx\n",
- length_seg, addr, (addr + length_seg) - 1);
-
- if (!length_seg)
- goto out;
-
- if (addr & (PAGE_SIZE - 1)) {
- length =
- min((int) (PAGE_SIZE - (addr & (PAGE_SIZE - 1))),
- length_seg);
- ZFCP_LOG_TRACE
- ("address 0x%lx not on page boundary, length=0x%x\n",
- (unsigned long) addr, length);
- retval =
- zfcp_create_sbale(addr, length, length_total, length_min,
- length_max, buffer_index, buffer_first,
- buffer_last, buffere_index, buffer,
- sbtype);
- if (retval) {
- /* no resources */
- goto out;
- }
- addr += length;
- length = length_seg - length;
- } else
- length = length_seg;
-
- while (length > 0) {
- retval = zfcp_create_sbale(addr, min((int) PAGE_SIZE, length),
- length_total, length_min, length_max,
- buffer_index, buffer_first,
- buffer_last, buffere_index, buffer,
- sbtype);
- if (*buffere_index > ZFCP_LAST_SBALE_PER_SBAL)
- ZFCP_LOG_NORMAL("bug: Filling output buffers with SCSI "
- "data failed. Index ran out of bounds. "
- "(debug info %d)\n", *buffere_index);
- if (retval) {
- /* no resources */
- goto out;
- }
- length -= PAGE_SIZE;
- addr += PAGE_SIZE;
- }
- out:
- return retval;
-}
-
-/**
- * zfcp_create_sbale - creates a single SBALE
- * @addr: begin of this buffer segment
- * @length: length of this buffer segment
- * @length_total: total length of buffer
- * @length_min: roll back if generated buffer smaller than this
- * @length_max: sum of all SBALEs (count) not larger than this
- * @buffer_index: position of current BUFFER
- * @buffer_first: first BUFFER used for this buffer
- * @buffer_last: last BUFFER allowed for this buffer
- * @buffere_index: position of current BUFFERE of current BUFFER
- * @buffer: begin of SBAL array of request queue
- * @sbtype: storage-block type
- */
-static int
-zfcp_create_sbale(unsigned long addr, int length, int *length_total,
- int length_min, int length_max, int *buffer_index,
- int buffer_first, int buffer_last, int *buffere_index,
- struct qdio_buffer *buffer[], char sbtype)
-{
- int retval = 0;
- int length_real, residual;
- int buffers_used;
-
- volatile struct qdio_buffer_element *buffere =
- &(buffer[*buffer_index]->element[*buffere_index]);
-
- /* check whether we hit the limit */
- residual = length_max - *length_total;
- if (residual == 0) {
- ZFCP_LOG_TRACE("skip remaining %i bytes since length_max hit\n",
- length);
- goto out;
- }
- length_real = min(length, residual);
-
- /*
- * figure out next BUFFERE
- * (first BUFFERE of first BUFFER is skipped -
- * this is ok since it is reserved for the QTCB)
- */
- if (*buffere_index == ZFCP_LAST_SBALE_PER_SBAL) {
- /* last BUFFERE in this BUFFER */
- buffere->flags |= SBAL_FLAGS_LAST_ENTRY;
- /* need further BUFFER */
- if (*buffer_index == buffer_last) {
- /* queue full or last allowed BUFFER */
- buffers_used = (buffer_last - buffer_first) + 1;
- /* avoid modulo operation on negative value */
- buffers_used += QDIO_MAX_BUFFERS_PER_Q;
- buffers_used %= QDIO_MAX_BUFFERS_PER_Q;
- ZFCP_LOG_DEBUG("reached limit of number of BUFFERs "
- "allowed for this request\n");
- /* FIXME (design) - This check is wrong and enforces the
- * use of one SBALE less than possible
- */
- if ((*length_total < length_min)
- || (buffers_used < ZFCP_MAX_SBALS_PER_REQ)) {
- ZFCP_LOG_DEBUG("Rolling back SCSI command as "
- "there are insufficient buffers "
- "to cover the minimum required "
- "amount of data\n");
- /*
- * roll back complete list of BUFFERs generated
- * from the scatter-gather list associated
- * with this SCSI command
- */
- zfcp_qdio_zero_sbals(buffer,
- buffer_first,
- buffers_used);
- *length_total = 0;
- } else {
- /* DEBUG */
- ZFCP_LOG_NORMAL("Not enough buffers available. "
- "Can only transfer %i bytes of "
- "data\n",
- *length_total);
- }
- retval = -ENOMEM;
- goto out;
- } else { /* *buffer_index != buffer_last */
- /* chain BUFFERs */
- *buffere_index = 0;
- buffere =
- &(buffer[*buffer_index]->element[*buffere_index]);
- buffere->flags |= SBAL_FLAGS0_MORE_SBALS;
- (*buffer_index)++;
- *buffer_index %= QDIO_MAX_BUFFERS_PER_Q;
- buffere =
- &(buffer[*buffer_index]->element[*buffere_index]);
- buffere->flags |= sbtype;
- ZFCP_LOG_DEBUG
- ("Chaining previous BUFFER %i to BUFFER %i\n",
- ((*buffer_index !=
- 0) ? *buffer_index - 1 : QDIO_MAX_BUFFERS_PER_Q -
- 1), *buffer_index);
- }
- } else { /* *buffere_index != (QDIO_MAX_ELEMENTS_PER_BUFFER - 1) */
- (*buffere_index)++;
- buffere = &(buffer[*buffer_index]->element[*buffere_index]);
- }
-
- /* ok, found a place for this piece, put it there */
- buffere->addr = (void *) addr;
- buffere->length = length_real;
-
-#ifdef ZFCP_STAT_REQSIZES
- if (sbtype == SBAL_FLAGS0_TYPE_READ)
- zfcp_statistics_inc(&zfcp_data.read_sg_head, length_real);
- else
- zfcp_statistics_inc(&zfcp_data.write_sg_head, length_real);
-#endif
-
- ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) addr, length_real);
- ZFCP_LOG_TRACE("BUFFER no %i (0x%lx) BUFFERE no %i (0x%lx): BUFFERE "
- "data addr 0x%lx, BUFFERE length %i, BUFFER type %i\n",
- *buffer_index,
- (unsigned long) &buffer[*buffer_index], *buffere_index,
- (unsigned long) buffere, addr, length_real, sbtype);
- *length_total += length_real;
- out:
- return retval;
-}
-
-/*
- * function: zfcp_create_sbals_from_sg
- *
- * purpose: walks through scatter-gather list of specified SCSI command
- * and creates a corresponding list of SBALs
- *
- * returns: size of generated buffer in bytes
- *
- * context:
- */
-int
-zfcp_create_sbals_from_sg(struct zfcp_fsf_req *fsf_req, Scsi_Cmnd * scpnt,
- char sbtype, /* storage-block type */
- int length_min, /* roll back if generated buffer */
- int buffer_max) /* max numbers of BUFFERs */
-{
- int length_total = 0;
- int buffer_index = 0;
- int buffer_last = 0;
- int buffere_index = 1; /* elements 0 and 1 are req-id and qtcb */
- volatile struct qdio_buffer_element *buffere = NULL;
- struct zfcp_qdio_queue *req_q = NULL;
- int length_max = scpnt->request_bufflen;
-
- req_q = &fsf_req->adapter->request_queue;
-
- buffer_index = req_q->free_index;
- buffer_last = req_q->free_index +
- min(buffer_max, atomic_read(&req_q->free_count)) - 1;
- buffer_last %= QDIO_MAX_BUFFERS_PER_Q;
-
- ZFCP_LOG_TRACE
- ("total SCSI data buffer size is (scpnt->request_bufflen) %i\n",
- scpnt->request_bufflen);
- ZFCP_LOG_TRACE
- ("BUFFERs from (buffer_index)%i to (buffer_last)%i available\n",
- buffer_index, buffer_last);
- ZFCP_LOG_TRACE("buffer_max=%d, req_q->free_count=%d\n", buffer_max,
- atomic_read(&req_q->free_count));
-
- if (scpnt->use_sg) {
- int sg_index;
- struct scatterlist *list
- = (struct scatterlist *) scpnt->request_buffer;
-
- ZFCP_LOG_DEBUG("%i (scpnt->use_sg) scatter-gather segments\n",
- scpnt->use_sg);
-
- // length_max+=0x2100;
-
-#ifdef ZFCP_STAT_REQSIZES
- if (sbtype == SBAL_FLAGS0_TYPE_READ)
- zfcp_statistics_inc(&zfcp_data.read_sguse_head,
- scpnt->use_sg);
- else
- zfcp_statistics_inc(&zfcp_data.write_sguse_head,
- scpnt->use_sg);
-#endif
-
- for (sg_index = 0; sg_index < scpnt->use_sg; sg_index++, list++)
- {
- if (zfcp_create_sbales_from_segment(
- (page_to_pfn (list->page) << PAGE_SHIFT) +
- list->offset,
- list->length,
- &length_total,
- length_min,
- length_max,
- &buffer_index,
- &buffere_index,
- req_q->free_index,
- buffer_last,
- req_q->buffer,
- sbtype))
- break;
- }
- } else {
- ZFCP_LOG_DEBUG("no scatter-gather list\n");
-#ifdef ZFCP_STAT_REQSIZES
- if (sbtype == SBAL_FLAGS0_TYPE_READ)
- zfcp_statistics_inc(&zfcp_data.read_sguse_head, 1);
- else
- zfcp_statistics_inc(&zfcp_data.write_sguse_head, 1);
-#endif
- zfcp_create_sbales_from_segment(
- (unsigned long) scpnt->request_buffer,
- scpnt->request_bufflen,
- &length_total,
- length_min,
- length_max,
- &buffer_index,
- &buffere_index,
- req_q->free_index,
- buffer_last,
- req_q->buffer,
- sbtype);
- }
-
- fsf_req->sbal_index = req_q->free_index;
-
- if (buffer_index >= fsf_req->sbal_index) {
- fsf_req->sbal_count = (buffer_index - fsf_req->sbal_index) + 1;
- } else {
- fsf_req->sbal_count =
- (QDIO_MAX_BUFFERS_PER_Q - fsf_req->sbal_index) +
- buffer_index + 1;
- }
- /* HACK */
- if ((scpnt->request_bufflen != 0) && (length_total == 0))
- goto out;
-
-#ifdef ZFCP_STAT_REQSIZES
- if (sbtype == SBAL_FLAGS0_TYPE_READ)
- zfcp_statistics_inc(&zfcp_data.read_req_head, length_total);
- else
- zfcp_statistics_inc(&zfcp_data.write_req_head, length_total);
-#endif
-
- buffere = &(req_q->buffer[buffer_index]->element[buffere_index]);
- buffere->flags |= SBAL_FLAGS_LAST_ENTRY;
- out:
- ZFCP_LOG_DEBUG("%i BUFFER(s) from %i to %i needed\n",
- fsf_req->sbal_count, fsf_req->sbal_index, buffer_index);
- ZFCP_LOG_TRACE("total QDIO data buffer size is %i\n", length_total);
-
- return length_total;
-}
-
void
zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *adapter)
{
};
#undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
*
* sysfs adapter related routines
*
- * Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
+ * (C) Copyright IBM Corp. 2003, 2004
+ *
* Authors:
* Martin Peschke <mpeschke@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.26 $"
+#define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.30 $"
#include <asm/ccwdev.h>
#include "zfcp_ext.h"
#include "zfcp_def.h"
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG
-#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_CONFIG
static const char fc_topologies[5][25] = {
{"<error>"},
ZFCP_DEFINE_ADAPTER_ATTR(wwnn, "0x%016llx\n", adapter->wwnn);
ZFCP_DEFINE_ADAPTER_ATTR(wwpn, "0x%016llx\n", adapter->wwpn);
ZFCP_DEFINE_ADAPTER_ATTR(s_id, "0x%06x\n", adapter->s_id);
-ZFCP_DEFINE_ADAPTER_ATTR(hw_version, "0x%04x\n", adapter->hydra_version);
+ZFCP_DEFINE_ADAPTER_ATTR(card_version, "0x%04x\n", adapter->hydra_version);
ZFCP_DEFINE_ADAPTER_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version);
ZFCP_DEFINE_ADAPTER_ATTR(fc_link_speed, "%d Gb/s\n", adapter->fc_link_speed);
ZFCP_DEFINE_ADAPTER_ATTR(fc_service_class, "%d\n", adapter->fc_service_class);
ZFCP_DEFINE_ADAPTER_ATTR(fc_topology, "%s\n",
fc_topologies[adapter->fc_topology]);
+ZFCP_DEFINE_ADAPTER_ATTR(hardware_version, "0x%08x\n",
+ adapter->hardware_version);
+ZFCP_DEFINE_ADAPTER_ATTR(serial_number, "%17s\n", adapter->serial_number);
/**
* zfcp_sysfs_adapter_in_recovery_show - recovery state of adapter
goto out;
}
- /* restart error recovery only if adapter is online */
- if (adapter->ccw_device->online != 1) {
- retval = -ENXIO;
- goto out;
- }
zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING,
ZFCP_SET);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
&dev_attr_wwnn.attr,
&dev_attr_wwpn.attr,
&dev_attr_s_id.attr,
- &dev_attr_hw_version.attr,
+ &dev_attr_card_version.attr,
&dev_attr_lic_version.attr,
&dev_attr_fc_link_speed.attr,
&dev_attr_fc_service_class.attr,
&dev_attr_fc_topology.attr,
&dev_attr_scsi_host_no.attr,
&dev_attr_status.attr,
+ &dev_attr_hardware_version.attr,
+ &dev_attr_serial_number.attr,
NULL
};
}
#undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
*
* sysfs driver related routines
*
- * Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
+ * (C) Copyright IBM Corp. 2003, 2004
+ *
* Authors:
* Martin Peschke <mpeschke@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#define ZFCP_SYSFS_DRIVER_C_REVISION "$Revision: 1.8 $"
+#define ZFCP_SYSFS_DRIVER_C_REVISION "$Revision: 1.12 $"
#include <asm/ccwdev.h>
#include "zfcp_ext.h"
#include "zfcp_def.h"
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG
-#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_CONFIG
/**
* ZFCP_DEFINE_DRIVER_ATTR - define for all loglevels sysfs attributes
static ssize_t zfcp_sysfs_loglevel_##_name##_show(struct device_driver *dev, \
char *buf) \
{ \
- return sprintf(buf,"%d\n", ZFCP_LOG_VALUE(ZFCP_LOG_AREA_##_define)); \
+ return sprintf(buf,"%d\n", \
+ ZFCP_GET_LOG_VALUE(ZFCP_LOG_AREA_##_define)); \
} \
\
static DRIVER_ATTR(loglevel_##_name, S_IWUSR | S_IRUGO, \
ZFCP_DEFINE_DRIVER_ATTR(erp, ERP);
ZFCP_DEFINE_DRIVER_ATTR(fc, FC);
+static ssize_t zfcp_sysfs_version_show(struct device_driver *dev,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", ZFCP_VERSION);
+}
+
+static DRIVER_ATTR(version, S_IRUGO, zfcp_sysfs_version_show, NULL);
+
static struct attribute *zfcp_driver_attrs[] = {
&driver_attr_loglevel_other.attr,
&driver_attr_loglevel_scsi.attr,
&driver_attr_loglevel_qdio.attr,
&driver_attr_loglevel_erp.attr,
&driver_attr_loglevel_fc.attr,
+ &driver_attr_version.attr,
NULL
};
}
#undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
*
* sysfs port related routines
*
- * Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
+ * (C) Copyright IBM Corp. 2003, 2004
+ *
* Authors:
* Martin Peschke <mpeschke@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#define ZFCP_SYSFS_PORT_C_REVISION "$Revision: 1.32 $"
+#define ZFCP_SYSFS_PORT_C_REVISION "$Revision: 1.37 $"
#include <linux/init.h>
#include <linux/module.h>
#include "zfcp_def.h"
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG
-#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_CONFIG
/**
* zfcp_sysfs_port_release - gets called when a struct device port is released
goto out;
}
- /* restart error recovery only if adapter is online */
- if (port->adapter->ccw_device->online != 1) {
- retval = -ENXIO;
- goto out;
- }
zfcp_erp_modify_port_status(port, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_erp_wait(port->adapter);
static DEVICE_ATTR(in_recovery, S_IRUGO, zfcp_sysfs_port_in_recovery_show,
NULL);
+/**
+ * zfcp_port_common_attrs
+ * sysfs attributes that are common for all kind of fc ports.
+ */
static struct attribute *zfcp_port_common_attrs[] = {
&dev_attr_failed.attr,
&dev_attr_in_recovery.attr,
.attrs = zfcp_port_common_attrs,
};
+/**
+ * zfcp_port_no_ns_attrs
+ * sysfs attributes not to be used for nameserver ports.
+ */
static struct attribute *zfcp_port_no_ns_attrs[] = {
&dev_attr_unit_add.attr,
&dev_attr_unit_remove.attr,
}
#undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
*
* sysfs unit related routines
*
- * Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
+ * (C) Copyright IBM Corp. 2003, 2004
+ *
* Authors:
* Martin Peschke <mpeschke@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#define ZFCP_SYSFS_UNIT_C_REVISION "$Revision: 1.19 $"
+#define ZFCP_SYSFS_UNIT_C_REVISION "$Revision: 1.23 $"
#include <linux/init.h>
#include <linux/module.h>
#include "zfcp_def.h"
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG
-#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_CONFIG
/**
* zfcp_sysfs_unit_release - gets called when a struct device unit is released
goto out;
}
- /* restart error recovery only if adapter is online */
- if (unit->port->adapter->ccw_device->online != 1) {
- retval = -ENXIO;
- goto out;
- }
zfcp_erp_modify_unit_status(unit, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED);
+ zfcp_erp_wait(unit->port->adapter);
out:
up(&zfcp_data.config_sema);
return retval ? retval : count;
}
#undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX