From eb16bf916386853f8d2dde1b75d7162266dd5a0f Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Thu, 24 Jun 2010 18:03:27 +0000 Subject: [PATCH] Implement qlini_mode qla2xxx module parameter with ini_mode_force_reverse sysfs attribute instead of CONFIG_SCSI_QLA2XXX_TARGET_DISABLE_INI_MODE compile-time option for better flexibility. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1781 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- qla2x00t/Kconfig | 20 ++------ qla2x00t/qla2x00-target/README | 31 ++++++++++++ qla2x00t/qla2x_tgt.h | 34 ++++++------- qla2x00t/qla2x_tgt_def.h | 12 ++++- qla2x00t/qla_attr.c | 70 +++++++++++++++++++++++++++ qla2x00t/qla_def.h | 1 + qla2x00t/qla_gs.c | 9 ++-- qla2x00t/qla_init.c | 14 +++--- qla2x00t/qla_os.c | 87 ++++++++++++++++++++++++++++++++++ 9 files changed, 230 insertions(+), 48 deletions(-) diff --git a/qla2x00t/Kconfig b/qla2x00t/Kconfig index 3d59d14ff..da46dbbde 100644 --- a/qla2x00t/Kconfig +++ b/qla2x00t/Kconfig @@ -31,20 +31,8 @@ config SCSI_QLA2XXX_TARGET depends on SCSI_QLA_FC default y ---help--- - This option enables target mode hooks used by the SCST QLA2x00tgt driver. - Once the qla2x00tgt module is loaded, target mode can be enable via a - sysfs interface under scsi_host, thus enabling target mode for specific - cards. - You will also need the SCST middle level drivers from - http://scst.sourceforge.net/. + This option enables target mode hooks used by the SCST qla2x00t + driver. Once qla2x00tgt module is loaded, target mode for each + port can be enable via sysfs interface. -config SCSI_QLA2XXX_TARGET_DISABLE_INI_MODE - bool "Disable initiator mode for ports with enabled target mode" - depends on SCSI_QLA2XXX_TARGET - default y - ---help--- - This option disables initiator mode for hosts for which target mode was - enabled. In other words, it disables possibility to use both target and - initiator mode simultaneously on the same host. It is needed, because - some switches don't handle well ports with both target and initiator - modes enabled. + You will also need the SCST middle level for qla2x00t. diff --git a/qla2x00t/qla2x00-target/README b/qla2x00t/qla2x00-target/README index ddaebbf78..a1b629d60 100644 --- a/qla2x00t/qla2x00-target/README +++ b/qla2x00t/qla2x00-target/README @@ -107,6 +107,37 @@ http://sourceforge.net/mailarchive/forum.php?thread_name=4B4CD39F.6020401%40vlnb for more details why. +Initiator and target modes +-------------------------- + +When qla2xxx compiled with CONFIG_SCSI_QLA2XXX_TARGET enabled, it has +parameter "ini_mode", which determines when initiator mode will be +enabled. Possible values: + + - "exclusive" (default ) - initiator mode will be enabled on load, +disabled on enabling target mode and then on disabling target mode +enabled back. + + - "disabled" - initiator mode will never be enabled. + + - "enabled" - initiator mode will always stay enabled. + +Usage of mode "disabled" is recommended if you have incorrectly +functioning remote for your target initiators, which if they once seen a +port in initiator mode, later refuse to see it as a target. + +Use mode "enabled" if you need your QLA adapters to work in both +initiator and target modes at the same time. + +In all the modes you can at any time use sysfs attribute +ini_mode_force_reverse to force enable or disable initiator mode on any +particular port. Setting this attribute to 1 will reverse current status +of the initiator mode from enabled to disabled and vice versa. + +You can always see which modes are currently active in active_mode sysfs +attribute. + + Explicit conformation --------------------- diff --git a/qla2x00t/qla2x_tgt.h b/qla2x00t/qla2x_tgt.h index 09915a63f..b2ae54ea2 100644 --- a/qla2x00t/qla2x_tgt.h +++ b/qla2x00t/qla2x_tgt.h @@ -34,31 +34,27 @@ extern request_t *qla2x00_req_pkt(scsi_qla_host_t *ha); extern struct qla_tgt_data qla_target; -/* Called under HW lock */ -static inline void qla_set_tgt_mode(scsi_qla_host_t *ha) -{ -#ifdef CONFIG_SCSI_QLA2XXX_TARGET_DISABLE_INI_MODE - ha->host->active_mode = MODE_TARGET; -#else - ha->host->active_mode |= MODE_TARGET; -#endif -} - -/* Called under HW lock */ -static inline void qla_clear_tgt_mode(scsi_qla_host_t *ha) -{ -#ifdef CONFIG_SCSI_QLA2XXX_TARGET_DISABLE_INI_MODE - ha->host->active_mode = MODE_INITIATOR; -#else - ha->host->active_mode &= ~MODE_TARGET; -#endif -} +void qla_set_tgt_mode(scsi_qla_host_t *ha); +void qla_clear_tgt_mode(scsi_qla_host_t *ha); static inline bool qla_tgt_mode_enabled(scsi_qla_host_t *ha) { return ha->host->active_mode & MODE_TARGET; } +static inline bool qla_ini_mode_enabled(scsi_qla_host_t *ha) +{ + return ha->host->active_mode & MODE_INITIATOR; +} + +static inline void qla_reverse_ini_mode(scsi_qla_host_t *ha) +{ + if (ha->host->active_mode & MODE_INITIATOR) + ha->host->active_mode &= ~MODE_INITIATOR; + else + ha->host->active_mode |= MODE_INITIATOR; +} + /********************************************************************\ * ISP Queue types left out of new QLogic driver (from old version) \********************************************************************/ diff --git a/qla2x00t/qla2x_tgt_def.h b/qla2x00t/qla2x_tgt_def.h index 9e57ffb4b..d1f1233e9 100644 --- a/qla2x00t/qla2x_tgt_def.h +++ b/qla2x00t/qla2x_tgt_def.h @@ -44,13 +44,21 @@ * Must be changed on any change in any initiator visible interfaces or * data in the target add-on */ -#define QLA2X_TARGET_MAGIC 265 +#define QLA2X_TARGET_MAGIC 267 /* * Must be changed on any change in any target visible interfaces or * data in the initiator */ -#define QLA2X_INITIATOR_MAGIC 57218 +#define QLA2X_INITIATOR_MAGIC 57219 + +#define QLA2X_INI_MODE_STR_EXCLUSIVE "exclusive" +#define QLA2X_INI_MODE_STR_DISABLED "disabled" +#define QLA2X_INI_MODE_STR_ENABLED "enabled" + +#define QLA2X_INI_MODE_EXCLUSIVE 0 +#define QLA2X_INI_MODE_DISABLED 1 +#define QLA2X_INI_MODE_ENABLED 2 #define QLA2X00_COMMAND_COUNT_INIT 250 #define QLA2X00_IMMED_NOTIFY_COUNT_INIT 250 diff --git a/qla2x00t/qla_attr.c b/qla2x00t/qla_attr.c index f70d7201d..613823d42 100644 --- a/qla2x00t/qla_attr.c +++ b/qla2x00t/qla_attr.c @@ -214,6 +214,75 @@ static DEVICE_ATTR(explicit_conform_enabled, #endif /* CONFIG_SCST_PROC */ +static ssize_t +qla2x00_show_ini_mode_force_reverse(struct device *dev, + struct device_attribute *attr, char *buffer) +{ + scsi_qla_host_t *ha = shost_priv(class_to_shost(dev)); + ulong max_size = PAGE_SIZE; + ulong size; + + size = scnprintf(buffer, max_size, "%x\n", ha->ini_mode_force_reverse); + + return size; +} + +static ssize_t +qla2x00_store_ini_mode_force_reverse(struct device *dev, + struct device_attribute *attr, const char *buffer, size_t size) +{ + struct scsi_qla_host *ha = shost_priv(class_to_shost(dev)); + unsigned long flags; + + if (buffer == NULL) + return size; + + spin_lock_irqsave(&ha->hardware_lock, flags); + + switch (buffer[0]) { + case '0': + if (!ha->ini_mode_force_reverse) + goto out_unlock; + ha->ini_mode_force_reverse = 0; + qla_printk(KERN_INFO, ha, "qla2xxx(%ld): initiator mode force " + "reverse disabled\n", ha->instance); + qla_reverse_ini_mode(ha); + break; + case '1': + if (ha->ini_mode_force_reverse) + goto out_unlock; + ha->ini_mode_force_reverse = 1; + qla_printk(KERN_INFO, ha, "qla2xxx(%ld): initiator mode force " + "reverse enabled\n", ha->instance); + qla_reverse_ini_mode(ha); + break; + default: +#if defined(QL_DEBUG_LEVEL_9) || defined(QL_DEBUG_LEVEL_11) + qla_printk(KERN_ERR, ha, "%s: Requested action not understood: " + "%s\n", __func__, buffer); +#endif + break; + } + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + qla2xxx_wake_dpc(ha); + qla2x00_wait_for_hba_online(ha); + +out: + return size; + +out_unlock: + spin_unlock_irqrestore(&ha->hardware_lock, flags); + goto out; +} + +static DEVICE_ATTR(ini_mode_force_reverse, + S_IRUGO|S_IWUSR, + qla2x00_show_ini_mode_force_reverse, + qla2x00_store_ini_mode_force_reverse); + static ssize_t qla2x00_show_resource_counts(struct device *dev, struct device_attribute *attr, char *buffer) @@ -1338,6 +1407,7 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_target_mode_enabled, &dev_attr_explicit_conform_enabled, #endif + &dev_attr_ini_mode_force_reverse, &dev_attr_resource_counts, &dev_attr_port_database, #endif diff --git a/qla2x00t/qla_def.h b/qla2x00t/qla_def.h index 03a500198..b103059f2 100644 --- a/qla2x00t/qla_def.h +++ b/qla2x00t/qla_def.h @@ -2352,6 +2352,7 @@ typedef struct scsi_qla_host { #ifdef CONFIG_SCSI_QLA2XXX_TARGET unsigned int enable_explicit_conf :1; unsigned int host_shutting_down :1; + unsigned int ini_mode_force_reverse :1; dma_addr_t atio_dma; /* Physical address. */ atio_t *atio_ring; /* Base virtual address */ diff --git a/qla2x00t/qla_gs.c b/qla2x00t/qla_gs.c index 5704ce98f..8c2d1ae4d 100644 --- a/qla2x00t/qla_gs.c +++ b/qla2x00t/qla_gs.c @@ -546,11 +546,10 @@ qla2x00_rff_id(scsi_qla_host_t *ha) * FC-4 Feature bit 0 indicates target functionality to the name server. */ if (qla_tgt_mode_enabled(ha)) { -#ifdef CONFIG_SCSI_QLA2XXX_TARGET_DISABLE_INI_MODE - ct_req->req.rff_id.fc4_feature = BIT_0; -#else - ct_req->req.rff_id.fc4_feature = BIT_0 | BIT_1; -#endif + if (qla_ini_mode_enabled(ha)) + ct_req->req.rff_id.fc4_feature = BIT_0 | BIT_1; + else + ct_req->req.rff_id.fc4_feature = BIT_0; } else #endif ct_req->req.rff_id.fc4_feature = BIT_1; diff --git a/qla2x00t/qla_init.c b/qla2x00t/qla_init.c index f8c68ec13..0629830ce 100644 --- a/qla2x00t/qla_init.c +++ b/qla2x00t/qla_init.c @@ -1754,9 +1754,10 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) /* Enable target mode */ nv->firmware_options[0] |= BIT_4; -#ifdef CONFIG_SCSI_QLA2XXX_TARGET_DISABLE_INI_MODE - nv->firmware_options[0] |= BIT_5; -#endif + + /* Disable ini mode, if requested */ + if (!qla_ini_mode_enabled(ha)) + nv->firmware_options[0] |= BIT_5; /* Disable Full Login after LIP */ nv->firmware_options[1] &= ~BIT_5; @@ -3745,9 +3746,10 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) /* Enable target mode */ nv->firmware_options_1 |= __constant_cpu_to_le32(BIT_4); -#ifdef CONFIG_SCSI_QLA2XXX_TARGET_DISABLE_INI_MODE - nv->firmware_options_1 |= __constant_cpu_to_le32(BIT_5); -#endif + + /* Disable ini mode, if requested */ + if (!qla_ini_mode_enabled(ha)) + nv->firmware_options_1 |= __constant_cpu_to_le32(BIT_5); /* Disable Full Login after LIP */ nv->firmware_options_1 &= __constant_cpu_to_le32(~BIT_13); diff --git a/qla2x00t/qla_os.c b/qla2x00t/qla_os.c index 1c81dc433..6dae1d3d7 100644 --- a/qla2x00t/qla_os.c +++ b/qla2x00t/qla_os.c @@ -36,6 +36,18 @@ struct qla_tgt_data qla_target; */ static LIST_HEAD(qla_ha_list); static DEFINE_MUTEX(qla_ha_list_mutex); + +static char *qlini_mode = QLA2X_INI_MODE_STR_EXCLUSIVE; +module_param(qlini_mode, charp, S_IRUGO); +MODULE_PARM_DESC(qlini_mode, + "Determines when initiator mode will be enabled. Possible values: " + "\"exclusive\" (default) - initiator mode will be enabled on load, " + "disabled on enabling target mode and then on disabling target mode " + "enabled back; " + "\"disabled\" - initiator mode will never be enabled; " + "\"enabled\" - initiator mode will always stay enabled."); + +static int ql2x_ini_mode = QLA2X_INI_MODE_EXCLUSIVE; #endif /* @@ -3073,6 +3085,76 @@ static struct pci_driver qla2xxx_pci_driver = { .err_handler = &qla2xxx_err_handler, }; +#ifdef CONFIG_SCSI_QLA2XXX_TARGET + +/* Must be called under HW lock */ +void qla_set_tgt_mode(scsi_qla_host_t *ha) +{ + switch (ql2x_ini_mode) { + case QLA2X_INI_MODE_DISABLED: + case QLA2X_INI_MODE_EXCLUSIVE: + ha->host->active_mode = MODE_TARGET; + break; + case QLA2X_INI_MODE_ENABLED: + ha->host->active_mode |= MODE_TARGET; + break; + default: + BUG(); + break; + } + + if (ha->ini_mode_force_reverse) + qla_reverse_ini_mode(ha); + + return; +} +EXPORT_SYMBOL(qla_set_tgt_mode); + +/* Must be called under HW lock */ +void qla_clear_tgt_mode(scsi_qla_host_t *ha) +{ + switch (ql2x_ini_mode) { + case QLA2X_INI_MODE_DISABLED: + ha->host->active_mode = MODE_UNKNOWN; + break; + case QLA2X_INI_MODE_EXCLUSIVE: + ha->host->active_mode = MODE_INITIATOR; + break; + case QLA2X_INI_MODE_ENABLED: + ha->host->active_mode &= ~MODE_TARGET; + break; + default: + BUG(); + break; + } + + if (ha->ini_mode_force_reverse) + qla_reverse_ini_mode(ha); + + return; +} +EXPORT_SYMBOL(qla_clear_tgt_mode); + +static bool __init qla2x00_parse_ini_mode(void) +{ + if (strcasecmp(qlini_mode, QLA2X_INI_MODE_STR_EXCLUSIVE) == 0) + ql2x_ini_mode = QLA2X_INI_MODE_EXCLUSIVE; + else if (strcasecmp(qlini_mode, QLA2X_INI_MODE_STR_DISABLED) == 0) + ql2x_ini_mode = QLA2X_INI_MODE_DISABLED; + else if (strcasecmp(qlini_mode, QLA2X_INI_MODE_STR_ENABLED) == 0) + ql2x_ini_mode = QLA2X_INI_MODE_ENABLED; + else + return false; + + return true; +} +#else +static inline bool qla2x00_parse_ini_mode(void) +{ + return true; +} +#endif + /** * qla2x00_module_init - Module initialization. **/ @@ -3100,6 +3182,11 @@ qla2x00_module_init(void) ql2xextended_error_logging = 1; #endif + if (!qla2x00_parse_ini_mode()) { + printk("Wrong qlini_mode value %s\n", qlini_mode); + return -EINVAL; + } + /* Allocate cache for SRBs. */ srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0, SLAB_HWCACHE_ALIGN, NULL);