#include "qla_devtbl.h"
+#ifdef CONFIG_SPARC
+#include <asm/prom.h>
+#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) \
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
- rval = ha->isp_ops.pci_config(ha);
+ rval = ha->isp_ops->pci_config(ha);
if (rval) {
DEBUG2(printk("scsi(%ld): Unable to configure PCI space.\n",
ha->host_no));
return (rval);
}
- ha->isp_ops.reset_chip(ha);
+ ha->isp_ops->reset_chip(ha);
- ha->isp_ops.get_flash_version(ha, ha->request_ring);
+ ha->isp_ops->get_flash_version(ha, ha->request_ring);
qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
- rval = ha->isp_ops.nvram_config(ha);
- if (rval) {
- DEBUG2(printk("scsi(%ld): Unable to verify NVRAM data.\n",
- ha->host_no));
- return rval;
- }
+ ha->isp_ops->nvram_config(ha);
if (ha->flags.disable_serdes) {
/* Mask HBA via NVRAM settings? */
qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
- rval = ha->isp_ops.chip_diag(ha);
+ rval = ha->isp_ops->chip_diag(ha);
if (rval)
return (rval);
rval = qla2x00_setup_chip(ha);
int
qla2100_pci_config(scsi_qla_host_t *ha)
{
- uint16_t w, mwi;
+ uint16_t w;
uint32_t d;
unsigned long flags;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
pci_set_master(ha->pdev);
- mwi = 0;
- if (pci_set_mwi(ha->pdev))
- mwi = PCI_COMMAND_INVALIDATE;
+ pci_try_set_mwi(ha->pdev);
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
- w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+ w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
pci_write_config_word(ha->pdev, PCI_COMMAND, w);
/* Reset expansion ROM address decode enable */
int
qla2300_pci_config(scsi_qla_host_t *ha)
{
- uint16_t w, mwi;
+ uint16_t w;
uint32_t d;
unsigned long flags = 0;
uint32_t cnt;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
pci_set_master(ha->pdev);
- mwi = 0;
- if (pci_set_mwi(ha->pdev))
- mwi = PCI_COMMAND_INVALIDATE;
+ pci_try_set_mwi(ha->pdev);
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
- w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+ w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
if (IS_QLA2322(ha) || IS_QLA6322(ha))
w &= ~PCI_COMMAND_INTX_DISABLE;
+ pci_write_config_word(ha->pdev, PCI_COMMAND, w);
/*
* If this is a 2300 card and not 2312, reset the
ha->fb_rev = RD_FB_CMD_REG(ha, reg);
if (ha->fb_rev == FPM_2300)
- w &= ~PCI_COMMAND_INVALIDATE;
+ pci_clear_mwi(ha->pdev);
/* Deselect FPM registers. */
WRT_REG_WORD(®->ctrl_status, 0x0);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
- pci_write_config_word(ha->pdev, PCI_COMMAND, w);
pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
int
qla24xx_pci_config(scsi_qla_host_t *ha)
{
- uint16_t w, mwi;
+ uint16_t w;
uint32_t d;
unsigned long flags = 0;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
- int pcix_cmd_reg, pcie_dctl_reg;
pci_set_master(ha->pdev);
- mwi = 0;
- if (pci_set_mwi(ha->pdev))
- mwi = PCI_COMMAND_INVALIDATE;
+ pci_try_set_mwi(ha->pdev);
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
- w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+ w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
w &= ~PCI_COMMAND_INTX_DISABLE;
pci_write_config_word(ha->pdev, PCI_COMMAND, w);
pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
/* PCI-X -- adjust Maximum Memory Read Byte Count (2048). */
- pcix_cmd_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX);
- if (pcix_cmd_reg) {
- uint16_t pcix_cmd;
-
- pcix_cmd_reg += PCI_X_CMD;
- pci_read_config_word(ha->pdev, pcix_cmd_reg, &pcix_cmd);
- pcix_cmd &= ~PCI_X_CMD_MAX_READ;
- pcix_cmd |= 0x0008;
- pci_write_config_word(ha->pdev, pcix_cmd_reg, pcix_cmd);
- }
+ if (pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX))
+ pcix_set_mmrbc(ha->pdev, 2048);
/* PCIe -- adjust Maximum Read Request Size (2048). */
- pcie_dctl_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
- if (pcie_dctl_reg) {
- uint16_t pcie_dctl;
-
- pcie_dctl_reg += PCI_EXP_DEVCTL;
- pci_read_config_word(ha->pdev, pcie_dctl_reg, &pcie_dctl);
- pcie_dctl &= ~PCI_EXP_DEVCTL_READRQ;
- pcie_dctl |= 0x4000;
- pci_write_config_word(ha->pdev, pcie_dctl_reg, pcie_dctl);
- }
+ if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
+ pcie_set_readrq(ha->pdev, 2048);
/* Reset expansion ROM address decode enable */
pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
d &= ~PCI_ROM_ADDRESS_ENABLE;
pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
- pci_read_config_word(ha->pdev, PCI_REVISION_ID, &ha->chip_revision);
+ ha->chip_revision = ha->pdev->revision;
/* Get PCI bus information. */
spin_lock_irqsave(&ha->hardware_lock, flags);
return QLA_SUCCESS;
}
+/**
+ * qla25xx_pci_config() - Setup ISP25xx PCI configuration registers.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+int
+qla25xx_pci_config(scsi_qla_host_t *ha)
+{
+ uint16_t w;
+ uint32_t d;
+
+ pci_set_master(ha->pdev);
+ pci_try_set_mwi(ha->pdev);
+
+ pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
+ w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+ w &= ~PCI_COMMAND_INTX_DISABLE;
+ pci_write_config_word(ha->pdev, PCI_COMMAND, w);
+
+ /* PCIe -- adjust Maximum Read Request Size (2048). */
+ if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
+ pcie_set_readrq(ha->pdev, 2048);
+
+ /* Reset expansion ROM address decode enable */
+ pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
+ d &= ~PCI_ROM_ADDRESS_ENABLE;
+ pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
+
+ ha->chip_revision = ha->pdev->revision;
+
+ return QLA_SUCCESS;
+}
+
/**
* qla2x00_isp_firmware() - Choose firmware image.
* @ha: HA context
uint32_t cnt;
uint16_t cmd;
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
spin_lock_irqsave(&ha->hardware_lock, flags);
void
qla24xx_reset_chip(scsi_qla_host_t *ha)
{
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
/* Perform RISC reset. */
qla24xx_reset_risc(ha);
fixed_size = offsetof(struct qla2300_fw_dump, data_ram);
mem_size = (ha->fw_memory_size - 0x11000 + 1) *
sizeof(uint16_t);
- } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
- fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
+ } else if (IS_FWI2_CAPABLE(ha)) {
+ fixed_size = IS_QLA25XX(ha) ?
+ offsetof(struct qla25xx_fw_dump, ext_mem):
+ offsetof(struct qla24xx_fw_dump, ext_mem);
mem_size = (ha->fw_memory_size - 0x100000 + 1) *
sizeof(uint32_t);
uint32_t srisc_address = 0;
/* Load firmware sequences */
- rval = ha->isp_ops.load_risc(ha, &srisc_address);
+ rval = ha->isp_ops->load_risc(ha, &srisc_address);
if (rval == QLA_SUCCESS) {
DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC "
"code.\n", ha->host_no));
&ha->fw_subminor_version,
&ha->fw_attributes, &ha->fw_memory_size);
qla2x00_resize_request_q(ha);
+ ha->flags.npiv_supported = 0;
+ if (IS_QLA24XX(ha) &&
+ (ha->fw_attributes & BIT_2))
+ ha->flags.npiv_supported = 1;
if (ql2xallocfwdump)
qla2x00_alloc_fw_dump(ha);
int rval;
unsigned long flags = 0;
int cnt;
+ struct mid_init_cb_24xx *mid_init_cb =
+ (struct mid_init_cb_24xx *) ha->init_cb;
spin_lock_irqsave(&ha->hardware_lock, flags);
/* Initialize response queue entries */
qla2x00_init_response_q_entries(ha);
- ha->isp_ops.config_rings(ha);
+ ha->isp_ops->config_rings(ha);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
/* Update any ISP specific firmware options before initialization. */
- ha->isp_ops.update_fw_options(ha);
+ ha->isp_ops->update_fw_options(ha);
DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
+
+ mid_init_cb->count = MAX_NUM_VPORT_FABRIC;
+ ha->max_npiv_vports = MAX_NUM_VPORT_FABRIC;
+
rval = qla2x00_init_firmware(ha, ha->init_cb_size);
if (rval) {
DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n",
int rval;
uint16_t loop_id;
uint16_t topo;
+ uint16_t sw_cap;
uint8_t al_pa;
uint8_t area;
uint8_t domain;
/* Get host addresses. */
rval = qla2x00_get_adapter_id(ha,
- &loop_id, &al_pa, &area, &domain, &topo);
+ &loop_id, &al_pa, &area, &domain, &topo, &sw_cap);
if (rval != QLA_SUCCESS) {
if (LOOP_TRANSITION(ha) || atomic_read(&ha->loop_down_timer) ||
(rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
/* initialize */
ha->min_external_loopid = SNS_FIRST_LOOP_ID;
ha->operating_mode = LOOP;
+ ha->switch_cap = 0;
switch (topo) {
case 0:
case 1:
DEBUG3(printk("scsi(%ld): HBA in FL topology.\n",
ha->host_no));
+ ha->switch_cap = sw_cap;
ha->current_topology = ISP_CFG_FL;
strcpy(connect_type, "(FL_Port)");
break;
case 3:
DEBUG3(printk("scsi(%ld): HBA in F P2P topology.\n",
ha->host_no));
+ ha->switch_cap = sw_cap;
ha->operating_mode = P2P;
ha->current_topology = ISP_CFG_F;
strcpy(connect_type, "(F_Port)");
}
}
+/* 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 device_node *dp = pci_device_to_OF_node(pdev);
+ const 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
+}
+
/*
* NVRAM configuration for ISP 2xxx
*
int
qla2x00_nvram_config(scsi_qla_host_t *ha)
{
+ int rval;
uint8_t chksum = 0;
uint16_t cnt;
uint8_t *dptr1, *dptr2;
init_cb_t *icb = ha->init_cb;
- nvram_t *nv = (nvram_t *)ha->request_ring;
- uint8_t *ptr = (uint8_t *)ha->request_ring;
+ nvram_t *nv = ha->nvram;
+ uint8_t *ptr = ha->nvram;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+ rval = QLA_SUCCESS;
+
/* Determine NVRAM starting address. */
ha->nvram_size = sizeof(nvram_t);
ha->nvram_base = 0;
ha->nvram_base = 0x80;
/* Get NVRAM data and calculate checksum. */
- ha->isp_ops.read_nvram(ha, ptr, ha->nvram_base, ha->nvram_size);
+ ha->isp_ops->read_nvram(ha, ptr, ha->nvram_base, ha->nvram_size);
for (cnt = 0, chksum = 0; cnt < ha->nvram_size; cnt++)
chksum += *ptr++;
DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
- DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring,
- ha->nvram_size));
+ DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
/* Bad NVRAM data, set defaults parameters. */
if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
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;
+ qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
+ "invalid -- WWPN) defaults.\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;
+
+ rval = 1;
}
#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
}
}
- return QLA_SUCCESS;
+ if (rval) {
+ DEBUG2_3(printk(KERN_WARNING
+ "scsi(%ld): NVRAM configuration failed!\n", ha->host_no));
+ }
+ return (rval);
}
static void
spin_unlock_irqrestore(&fcport->rport_lock, flags);
if (rport)
fc_remote_port_delete(rport);
-
}
/**
/* Setup fcport template structure. */
memset(fcport, 0, sizeof (fc_port_t));
fcport->ha = ha;
+ fcport->vp_idx = ha->vp_idx;
fcport->port_type = FCT_UNKNOWN;
fcport->loop_id = FC_NO_LOOP_ID;
atomic_set(&fcport->state, FCS_UNCONFIGURED);
char *id_iter;
uint16_t loop_id;
uint8_t domain, area, al_pa;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
found_devs = 0;
new_fcport = NULL;
/*
* Mark local devices that were present with FCF_DEVICE_LOST for now.
*/
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx != ha->vp_idx)
+ continue;
+
if (atomic_read(&fcport->state) == FCS_ONLINE &&
fcport->port_type != FCT_BROADCAST &&
(fcport->flags & FCF_FABRIC_DEVICE) == 0) {
new_fcport->d_id.b.area = area;
new_fcport->d_id.b.al_pa = al_pa;
new_fcport->loop_id = loop_id;
+ new_fcport->vp_idx = ha->vp_idx;
rval2 = qla2x00_get_port_database(ha, new_fcport, 0);
if (rval2 != QLA_SUCCESS) {
DEBUG2(printk("scsi(%ld): Failed to retrieve fcport "
/* Check for matching device in port list. */
found = 0;
fcport = NULL;
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx != ha->vp_idx)
+ continue;
+
if (memcmp(new_fcport->port_name, fcport->port_name,
WWN_SIZE))
continue;
if (!found) {
/* New device, add to fcports list. */
new_fcport->flags &= ~FCF_PERSISTENT_BOUND;
- list_add_tail(&new_fcport->list, &ha->fcports);
+ if (ha->parent) {
+ new_fcport->ha = ha;
+ new_fcport->vp_idx = ha->vp_idx;
+ list_add_tail(&new_fcport->vp_fcport,
+ &ha->vp_fcports);
+ }
+ list_add_tail(&new_fcport->list, &pha->fcports);
/* Allocate a new replacement fcport. */
fcport = new_fcport;
int rval;
uint16_t port_speed, mb[6];
- if (!IS_QLA24XX(ha))
+ if (!IS_IIDMA_CAPABLE(ha))
return;
switch (be16_to_cpu(fcport->fp_speed)) {
void
qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
{
+ scsi_qla_host_t *pha = to_qla_parent(ha);
+
fcport->ha = ha;
fcport->login_retry = 0;
- fcport->port_login_retry_count = ha->port_down_retry_count *
+ fcport->port_login_retry_count = pha->port_down_retry_count *
PORT_RETRY_TIME;
- atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
+ atomic_set(&fcport->port_down_timer, pha->port_down_retry_count *
PORT_RETRY_TIME);
fcport->flags &= ~FCF_LOGIN_NEEDED;
uint16_t mb[MAILBOX_REGISTER_COUNT];
uint16_t loop_id;
LIST_HEAD(new_fcports);
+ scsi_qla_host_t *pha = to_qla_parent(ha);
/* If FL port exists, then SNS is present */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
loop_id = NPH_F_PORT;
else
loop_id = SNS_FL_PORT;
qla2x00_fdmi_register(ha);
/* Ensure we are logged into the SNS. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
loop_id = NPH_SNS;
else
loop_id = SIMPLE_NAME_SERVER;
- ha->isp_ops.fabric_login(ha, loop_id, 0xff, 0xff,
+ ha->isp_ops->fabric_login(ha, loop_id, 0xff, 0xff,
0xfc, mb, BIT_1 | BIT_0);
if (mb[0] != MBS_COMMAND_COMPLETE) {
DEBUG2(qla_printk(KERN_INFO, ha,
* Logout all previous fabric devices marked lost, except
* tape devices.
*/
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx !=ha->vp_idx)
+ continue;
+
if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
break;
(fcport->flags & FCF_TAPE_PRESENT) == 0 &&
fcport->port_type != FCT_INITIATOR &&
fcport->port_type != FCT_BROADCAST) {
- ha->isp_ops.fabric_logout(ha,
+ ha->isp_ops->fabric_logout(ha,
fcport->loop_id,
fcport->d_id.b.domain,
fcport->d_id.b.area,
}
/* Starting free loop ID. */
- next_loopid = ha->min_external_loopid;
+ next_loopid = pha->min_external_loopid;
/*
* Scan through our port list and login entries that need to be
* logged in.
*/
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx != ha->vp_idx)
+ continue;
+
if (atomic_read(&ha->loop_down_timer) ||
test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
break;
break;
}
- /* Remove device from the new list and add it to DB */
- list_move_tail(&fcport->list, &ha->fcports);
-
/* Login and update database */
qla2x00_fabric_dev_login(ha, fcport, &next_loopid);
+
+ if (ha->parent) {
+ fcport->ha = ha;
+ fcport->vp_idx = ha->vp_idx;
+ list_add_tail(&fcport->vp_fcport,
+ &ha->vp_fcports);
+ list_move_tail(&fcport->list,
+ &ha->parent->fcports);
+ } else
+ list_move_tail(&fcport->list, &ha->fcports);
}
} while (0);
int swl_idx;
int first_dev, last_dev;
port_id_t wrap, nxt_d_id;
+ int vp_index;
+ int empty_vp_index;
+ int found_vp;
+ scsi_qla_host_t *vha;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
rval = QLA_SUCCESS;
return (QLA_MEMORY_ALLOC_FAILED);
}
new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
-
+ new_fcport->vp_idx = ha->vp_idx;
/* Set start port ID scan at adapter ID. */
first_dev = 1;
last_dev = 0;
/* Starting free loop ID. */
- loop_id = ha->min_external_loopid;
+ loop_id = pha->min_external_loopid;
for (; loop_id <= ha->last_loop_id; loop_id++) {
if (qla2x00_is_reserved_id(ha, loop_id))
continue;
break;
}
- /* Bypass if host adapter. */
- if (new_fcport->d_id.b24 == ha->d_id.b24)
+ /* Bypass if same physical adapter. */
+ if (new_fcport->d_id.b24 == pha->d_id.b24)
continue;
+ /* Bypass virtual ports of the same host. */
+ if (pha->num_vhosts) {
+ vp_index = find_next_bit(
+ (unsigned long *)pha->vp_idx_map,
+ MAX_MULTI_ID_FABRIC + 1, 1);
+
+ for (;vp_index <= MAX_MULTI_ID_FABRIC;
+ vp_index = find_next_bit(
+ (unsigned long *)pha->vp_idx_map,
+ MAX_MULTI_ID_FABRIC + 1, vp_index + 1)) {
+ empty_vp_index = 1;
+ found_vp = 0;
+ list_for_each_entry(vha, &pha->vp_list,
+ vp_list) {
+ if (vp_index == vha->vp_idx) {
+ empty_vp_index = 0;
+ found_vp = 1;
+ break;
+ }
+ }
+
+ if (empty_vp_index)
+ continue;
+
+ if (found_vp &&
+ new_fcport->d_id.b24 == vha->d_id.b24)
+ break;
+ }
+ if (vp_index <= MAX_MULTI_ID_FABRIC)
+ continue;
+ }
+
/* Bypass if same domain and area of adapter. */
if (((new_fcport->d_id.b24 & 0xffff00) ==
(ha->d_id.b24 & 0xffff00)) && ha->current_topology ==
/* Locate matching device in database. */
found = 0;
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (new_fcport->vp_idx != fcport->vp_idx)
+ continue;
if (memcmp(new_fcport->port_name, fcport->port_name,
WWN_SIZE))
continue;
(fcport->flags & FCF_TAPE_PRESENT) == 0 &&
fcport->port_type != FCT_INITIATOR &&
fcport->port_type != FCT_BROADCAST) {
- ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+ ha->isp_ops->fabric_logout(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
fcport->loop_id = FC_NO_LOOP_ID;
}
new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
new_fcport->d_id.b24 = nxt_d_id.b24;
+ new_fcport->vp_idx = ha->vp_idx;
}
kfree(swl);
int found;
fc_port_t *fcport;
uint16_t first_loop_id;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
rval = QLA_SUCCESS;
/* Check for loop ID being already in use. */
found = 0;
fcport = NULL;
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
if (fcport->loop_id == dev->loop_id && fcport != dev) {
/* ID possibly in use */
found++;
uint8_t rscn_out_iter;
uint8_t format;
port_id_t d_id;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
rval = QLA_RSCNS_HANDLED;
rval = QLA_SUCCESS;
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx != ha->vp_idx)
+ continue;
+
if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
(fcport->d_id.b24 & mask) != d_id.b24 ||
fcport->port_type == FCT_BROADCAST)
opts |= BIT_1;
rval = qla2x00_get_port_database(ha, fcport, opts);
if (rval != QLA_SUCCESS) {
- ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+ ha->isp_ops->fabric_logout(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
qla2x00_mark_device_lost(ha, fcport, 1, 0);
fcport->d_id.b.area, fcport->d_id.b.al_pa));
/* Login fcport on switch. */
- ha->isp_ops.fabric_login(ha, fcport->loop_id,
+ ha->isp_ops->fabric_login(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa, mb, BIT_0);
if (mb[0] == MBS_PORT_ID_USED) {
* dead.
*/
*next_loopid = fcport->loop_id;
- ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+ ha->isp_ops->fabric_logout(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
qla2x00_mark_device_lost(ha, fcport, 1, 0);
fcport->d_id.b.al_pa, fcport->loop_id, jiffies));
*next_loopid = fcport->loop_id;
- ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+ ha->isp_ops->fabric_logout(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
fcport->loop_id = FC_NO_LOOP_ID;
qla_printk(KERN_INFO, ha,
"Performing ISP error recovery - ha= %p.\n", ha);
- ha->isp_ops.reset_chip(ha);
+ ha->isp_ops->reset_chip(ha);
atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
- ha->isp_ops.get_flash_version(ha, ha->request_ring);
+ ha->isp_ops->get_flash_version(ha, ha->request_ring);
- rval = ha->isp_ops.nvram_config(ha);
- if (rval)
- goto isp_abort_retry;
+ ha->isp_ops->nvram_config(ha);
if (!qla2x00_restart_isp(ha)) {
clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
ha->flags.online = 1;
- ha->isp_ops.enable_intrs(ha);
+ ha->isp_ops->enable_intrs(ha);
ha->isp_abort_cnt = 0;
clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
}
}
} else { /* failed the ISP abort */
-isp_abort_retry:
ha->flags.online = 1;
if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
if (ha->isp_abort_cnt == 0) {
* The next call disables the board
* completely.
*/
- ha->isp_ops.reset_adapter(ha);
+ ha->isp_ops->reset_adapter(ha);
ha->flags.online = 0;
clear_bit(ISP_ABORT_RETRY,
&ha->dpc_flags);
/* If firmware needs to be loaded */
if (qla2x00_isp_firmware(ha)) {
ha->flags.online = 0;
- if (!(status = ha->isp_ops.chip_diag(ha))) {
+ if (!(status = ha->isp_ops->chip_diag(ha))) {
if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
status = qla2x00_setup_chip(ha);
goto done;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
ha->flags.online = 0;
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
spin_lock_irqsave(&ha->hardware_lock, flags);
WRT_REG_WORD(®->hccr, HCCR_RESET_RISC);
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
ha->flags.online = 0;
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
spin_lock_irqsave(&ha->hardware_lock, flags);
WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET);
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 device_node *dp = pci_device_to_OF_node(pdev);
+ const 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)
{
+ int rval;
struct init_cb_24xx *icb;
struct nvram_24xx *nv;
uint32_t *dptr;
uint32_t chksum;
uint16_t cnt;
+ rval = QLA_SUCCESS;
icb = (struct init_cb_24xx *)ha->init_cb;
- nv = (struct nvram_24xx *)ha->request_ring;
+ nv = ha->nvram;
/* Determine NVRAM starting address. */
ha->nvram_size = sizeof(struct nvram_24xx);
ha->vpd_base = FA_NVRAM_VPD1_ADDR;
}
- /* Get NVRAM data and calculate checksum. */
+ /* Get VPD data into cache */
+ ha->vpd = ha->nvram + VPD_OFFSET;
+ ha->isp_ops->read_nvram(ha, (uint8_t *)ha->vpd,
+ ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4);
+
+ /* Get NVRAM data into cache and calculate checksum. */
dptr = (uint32_t *)nv;
- ha->isp_ops.read_nvram(ha, (uint8_t *)dptr, ha->nvram_base,
+ ha->isp_ops->read_nvram(ha, (uint8_t *)dptr, ha->nvram_base,
ha->nvram_size);
for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
chksum += le32_to_cpu(*dptr++);
DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
- DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring,
- ha->nvram_size));
+ DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
/* Bad NVRAM data, set defaults parameters. */
if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
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;
+ qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
+ "invalid -- WWPN) defaults.\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);
+
+ rval = 1;
}
/* Reset Initialization control block */
ha->flags.process_response_queue = 1;
}
- return QLA_SUCCESS;
+ if (rval) {
+ DEBUG2_3(printk(KERN_WARNING
+ "scsi(%ld): NVRAM configuration failed!\n", ha->host_no));
+ }
+ return (rval);
}
static int
{
int ret, retries;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (!IS_FWI2_CAPABLE(ha))
+ return;
+ if (!ha->fw_major_version)
return;
ret = qla2x00_stop_firmware(ha);
ret = qla2x00_stop_firmware(ha);
}
}
+
+int
+qla24xx_configure_vhba(scsi_qla_host_t *ha)
+{
+ int rval = QLA_SUCCESS;
+ uint16_t mb[MAILBOX_REGISTER_COUNT];
+
+ if (!ha->parent)
+ return -EINVAL;
+
+ rval = qla2x00_fw_ready(ha);
+ if (rval == QLA_SUCCESS) {
+ clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
+ qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
+ }
+
+ ha->flags.management_server_logged_in = 0;
+
+ /* Login to SNS first */
+ qla24xx_login_fabric(ha, NPH_SNS, 0xff, 0xff, 0xfc,
+ mb, BIT_1);
+ if (mb[0] != MBS_COMMAND_COMPLETE) {
+ DEBUG15(qla_printk(KERN_INFO, ha,
+ "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
+ "mb[2]=%x mb[6]=%x mb[7]=%x\n", NPH_SNS,
+ mb[0], mb[1], mb[2], mb[6], mb[7]));
+ return (QLA_FUNCTION_FAILED);
+ }
+
+ atomic_set(&ha->loop_down_timer, 0);
+ atomic_set(&ha->loop_state, LOOP_UP);
+ set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+ set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+ rval = qla2x00_loop_resync(ha);
+
+ return rval;
+}