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