diff -Naur linux-2.6.git/drivers/scsi/qla2xxx/qla_gbl.h linux-2.6.git-nvram/drivers/scsi/qla2xxx/qla_gbl.h --- linux-2.6.git/drivers/scsi/qla2xxx/qla_gbl.h 2007-04-17 11:06:39.000000000 -0700 +++ linux-2.6.git-nvram/drivers/scsi/qla2xxx/qla_gbl.h 2007-04-17 11:07:24.000000000 -0700 @@ -62,6 +62,7 @@ extern int ql2xallocfwdump; extern int ql2xextended_error_logging; extern int ql2xqfullrampup; +extern int ql2xoverrideinvalidnvram; extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *); diff -Naur linux-2.6.git/drivers/scsi/qla2xxx/qla_init.c linux-2.6.git-nvram/drivers/scsi/qla2xxx/qla_init.c --- linux-2.6.git/drivers/scsi/qla2xxx/qla_init.c 2007-04-17 11:06:39.000000000 -0700 +++ linux-2.6.git-nvram/drivers/scsi/qla2xxx/qla_init.c 2007-04-17 11:07:24.000000000 -0700 @@ -11,6 +11,11 @@ #include "qla_devtbl.h" +#ifdef CONFIG_SPARC +#include +#include +#endif + /* XXX(hch): this is ugly, but we don't want to pull in exioctl.h */ #ifndef EXT_IS_LUN_BIT_SET #define EXT_IS_LUN_BIT_SET(P,L) \ @@ -1393,6 +1398,42 @@ } } +/* On sparc systems, obtain port and node WWN from firmware + * properties. + */ +static void qla2xxx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, nvram_t *nv) +{ +#ifdef CONFIG_SPARC + struct pci_dev *pdev = ha->pdev; + struct pcidev_cookie *pcp = pdev->sysdata; + struct device_node *dp = pcp->prom_node; + u8 *val; + int len; + + val = of_get_property(dp, "port-wwn", &len); + if (val && len >= WWN_SIZE) + memcpy(nv->port_name, val, WWN_SIZE); + + val = of_get_property(dp, "node-wwn", &len); + if (val && len >= WWN_SIZE) + memcpy(nv->node_name, val, WWN_SIZE); +#endif +} + +static inline int +qla2x00_override_invalid_nvram(scsi_qla_host_t *ha) +{ + if (!ql2xoverrideinvalidnvram) { + qla_printk(KERN_WARNING, ha, + "Reload the driver with the ql2xoverrideinvalidnvram \n"); + qla_printk(KERN_WARNING, ha, + " module parameter set to a non-zero value to ignore \n"); + qla_printk(KERN_WARNING, ha, + " this warning.\n"); + } + return ql2xoverrideinvalidnvram; +} + /* * NVRAM configuration for ISP 2xxx * @@ -1440,7 +1481,58 @@ qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: " "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0], nv->nvram_version); - return QLA_FUNCTION_FAILED; + if (!qla2x00_override_invalid_nvram(ha)) + return QLA_FUNCTION_FAILED; + qla_printk(KERN_WARNING, ha, "FC IDs may conflict and cause " + "miscommunication - please report this to QLogic " + "(linux-driver@qlogic.com).\n"); + + /* + * Set default initialization control block. + */ + memset(nv, 0, ha->nvram_size); + nv->parameter_block_version = ICB_VERSION; + + if (IS_QLA23XX(ha)) { + nv->firmware_options[0] = BIT_2 | BIT_1; + nv->firmware_options[1] = BIT_7 | BIT_5; + nv->add_firmware_options[0] = BIT_5; + nv->add_firmware_options[1] = BIT_5 | BIT_4; + nv->frame_payload_size = __constant_cpu_to_le16(2048); + nv->special_options[1] = BIT_7; + } else if (IS_QLA2200(ha)) { + nv->firmware_options[0] = BIT_2 | BIT_1; + nv->firmware_options[1] = BIT_7 | BIT_5; + nv->add_firmware_options[0] = BIT_5; + nv->add_firmware_options[1] = BIT_5 | BIT_4; + nv->frame_payload_size = __constant_cpu_to_le16(1024); + } else if (IS_QLA2100(ha)) { + nv->firmware_options[0] = BIT_3 | BIT_1; + nv->firmware_options[1] = BIT_5; + nv->frame_payload_size = __constant_cpu_to_le16(1024); + } + + nv->max_iocb_allocation = __constant_cpu_to_le16(256); + nv->execution_throttle = __constant_cpu_to_le16(16); + nv->retry_count = 8; + nv->retry_delay = 1; + + nv->port_name[0] = 33; + nv->port_name[3] = 224; + nv->port_name[4] = 139; + + qla2xxx_nvram_wwn_from_ofw(ha, nv); + + nv->login_timeout = 4; + + /* + * Set default host adapter parameters + */ + nv->host_p[1] = BIT_2; + nv->reset_delay = 5; + nv->port_down_retry_count = 8; + nv->max_luns_per_target = __constant_cpu_to_le16(8); + nv->link_down_timeout = 60; } #if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) @@ -3290,6 +3382,28 @@ spin_unlock_irqrestore(&ha->hardware_lock, flags); } +/* On sparc systems, obtain port and node WWN from firmware + * properties. + */ +static void qla24xx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, struct nvram_24xx *nv) +{ +#ifdef CONFIG_SPARC + struct pci_dev *pdev = ha->pdev; + struct pcidev_cookie *pcp = pdev->sysdata; + struct device_node *dp = pcp->prom_node; + u8 *val; + int len; + + val = of_get_property(dp, "port-wwn", &len); + if (val && len >= WWN_SIZE) + memcpy(nv->port_name, val, WWN_SIZE); + + val = of_get_property(dp, "node-wwn", &len); + if (val && len >= WWN_SIZE) + memcpy(nv->node_name, val, WWN_SIZE); +#endif +} + int qla24xx_nvram_config(scsi_qla_host_t *ha) { @@ -3332,7 +3446,53 @@ qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: " "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0], le16_to_cpu(nv->nvram_version)); - return QLA_FUNCTION_FAILED; + if (!qla2x00_override_invalid_nvram(ha)) + return QLA_FUNCTION_FAILED; + qla_printk(KERN_WARNING, ha, "FC IDs may conflict and cause " + "miscommunication - please report this to QLogic " + "(linux-driver@qlogic.com).\n"); + + /* + * Set default initialization control block. + */ + memset(nv, 0, ha->nvram_size); + nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION); + nv->version = __constant_cpu_to_le16(ICB_VERSION); + nv->frame_payload_size = __constant_cpu_to_le16(2048); + nv->execution_throttle = __constant_cpu_to_le16(0xFFFF); + nv->exchange_count = __constant_cpu_to_le16(0); + nv->hard_address = __constant_cpu_to_le16(124); + nv->port_name[0] = 0x21; + nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn); + nv->port_name[2] = 0x00; + nv->port_name[3] = 0xe0; + nv->port_name[4] = 0x8b; + nv->port_name[5] = 0x1c; + nv->port_name[6] = 0x55; + nv->port_name[7] = 0x86; + nv->node_name[0] = 0x20; + nv->node_name[1] = 0x00; + nv->node_name[2] = 0x00; + nv->node_name[3] = 0xe0; + nv->node_name[4] = 0x8b; + nv->node_name[5] = 0x1c; + nv->node_name[6] = 0x55; + nv->node_name[7] = 0x86; + qla24xx_nvram_wwn_from_ofw(ha, nv); + nv->login_retry_count = __constant_cpu_to_le16(8); + nv->interrupt_delay_timer = __constant_cpu_to_le16(0); + nv->login_timeout = __constant_cpu_to_le16(0); + nv->firmware_options_1 = + __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1); + nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4); + nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12); + nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13); + nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10); + nv->efi_parameters = __constant_cpu_to_le32(0); + nv->reset_delay = 5; + nv->max_luns_per_target = __constant_cpu_to_le16(128); + nv->port_down_retry_count = __constant_cpu_to_le16(30); + nv->link_down_timeout = __constant_cpu_to_le16(30); } /* Reset Initialization control block */ diff -Naur linux-2.6.git/drivers/scsi/qla2xxx/qla_os.c linux-2.6.git-nvram/drivers/scsi/qla2xxx/qla_os.c --- linux-2.6.git/drivers/scsi/qla2xxx/qla_os.c 2007-04-17 11:06:39.000000000 -0700 +++ linux-2.6.git-nvram/drivers/scsi/qla2xxx/qla_os.c 2007-04-17 11:07:24.000000000 -0700 @@ -90,6 +90,13 @@ "depth for a device after a queue-full condition has been " "detected. Default is 120 seconds."); +int ql2xoverrideinvalidnvram; +module_param(ql2xoverrideinvalidnvram, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xoverrideinvalidnvram, + "When set and upon detecting an invalid or non-present " + "NVRAM state, use doctored settings (potentially invalid) " + "to initialize the HBA."); + /* * SCSI host template entry points */ @@ -1575,9 +1582,7 @@ goto probe_failed; } - if (qla2x00_initialize_adapter(ha) && - !(ha->device_flags & DFLG_NO_CABLE)) { - + if (qla2x00_initialize_adapter(ha)) { qla_printk(KERN_WARNING, ha, "Failed to initialize adapter\n"); @@ -1733,7 +1738,8 @@ ha->flags.online = 0; /* Stop currently executing firmware. */ - qla2x00_try_to_stop_firmware(ha); + if (ha->fw_major_version) + qla2x00_try_to_stop_firmware(ha); /* turn-off interrupts on the card */ if (ha->interrupts_on)