Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/scsi/qla2xxx/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 113 kB image not shown  

SSL qla_nx.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * QLogic Fibre Channel HBA Driver
 * Copyright (c)  2003-2014 QLogic Corporation
 */

#include "qla_def.h"
#include <linux/delay.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/pci.h>
#include <linux/ratelimit.h>
#include <linux/vmalloc.h>
#include <scsi/scsi_tcq.h>

#define MASK(n)   ((1ULL<<(n))-1)
#define MN_WIN(addr) (((addr & 0x1fc0000) >> 1) | \
 ((addr >> 25) & 0x3ff))
#define OCM_WIN(addr) (((addr & 0x1ff0000) >> 1) | \
 ((addr >> 25) & 0x3ff))
#define MS_WIN(addr) (addr & 0x0ffc0000)
#define QLA82XX_PCI_MN_2M   (0)
#define QLA82XX_PCI_MS_2M   (0x80000)
#define QLA82XX_PCI_OCM0_2M (0xc0000)
#define VALID_OCM_ADDR(addr) (((addr) & 0x3f800) != 0x3f800)
#define GET_MEM_OFFS_2M(addr) (addr & MASK(18))
#define BLOCK_PROTECT_BITS 0x0F

/* CRB window related */
#define CRB_BLK(off) ((off >> 20) & 0x3f)
#define CRB_SUBBLK(off) ((off >> 16) & 0xf)
#define CRB_WINDOW_2M (0x130060)
#define QLA82XX_PCI_CAMQM_2M_END (0x04800800UL)
#define CRB_HI(off) ((qla82xx_crb_hub_agt[CRB_BLK(off)] << 20) | \
   ((off) & 0xf0000))
#define QLA82XX_PCI_CAMQM_2M_BASE (0x000ff800UL)
#define CRB_INDIRECT_2M (0x1e0000UL)

#define MAX_CRB_XFORM 60
static unsigned long crb_addr_xform[MAX_CRB_XFORM];
static int qla82xx_crb_table_initialized;

#define qla82xx_crb_addr_transform(name) \
 (crb_addr_xform[QLA82XX_HW_PX_MAP_CRB_##name] = \
 QLA82XX_HW_CRB_HUB_AGT_ADR_##name << 20)

const int MD_MIU_TEST_AGT_RDDATA[] = {
 0x410000A8, 0x410000AC,
 0x410000B8, 0x410000BC
};

static void qla82xx_crb_addr_transform_setup(void)
{
 qla82xx_crb_addr_transform(XDMA);
 qla82xx_crb_addr_transform(TIMR);
 qla82xx_crb_addr_transform(SRE);
 qla82xx_crb_addr_transform(SQN3);
 qla82xx_crb_addr_transform(SQN2);
 qla82xx_crb_addr_transform(SQN1);
 qla82xx_crb_addr_transform(SQN0);
 qla82xx_crb_addr_transform(SQS3);
 qla82xx_crb_addr_transform(SQS2);
 qla82xx_crb_addr_transform(SQS1);
 qla82xx_crb_addr_transform(SQS0);
 qla82xx_crb_addr_transform(RPMX7);
 qla82xx_crb_addr_transform(RPMX6);
 qla82xx_crb_addr_transform(RPMX5);
 qla82xx_crb_addr_transform(RPMX4);
 qla82xx_crb_addr_transform(RPMX3);
 qla82xx_crb_addr_transform(RPMX2);
 qla82xx_crb_addr_transform(RPMX1);
 qla82xx_crb_addr_transform(RPMX0);
 qla82xx_crb_addr_transform(ROMUSB);
 qla82xx_crb_addr_transform(SN);
 qla82xx_crb_addr_transform(QMN);
 qla82xx_crb_addr_transform(QMS);
 qla82xx_crb_addr_transform(PGNI);
 qla82xx_crb_addr_transform(PGND);
 qla82xx_crb_addr_transform(PGN3);
 qla82xx_crb_addr_transform(PGN2);
 qla82xx_crb_addr_transform(PGN1);
 qla82xx_crb_addr_transform(PGN0);
 qla82xx_crb_addr_transform(PGSI);
 qla82xx_crb_addr_transform(PGSD);
 qla82xx_crb_addr_transform(PGS3);
 qla82xx_crb_addr_transform(PGS2);
 qla82xx_crb_addr_transform(PGS1);
 qla82xx_crb_addr_transform(PGS0);
 qla82xx_crb_addr_transform(PS);
 qla82xx_crb_addr_transform(PH);
 qla82xx_crb_addr_transform(NIU);
 qla82xx_crb_addr_transform(I2Q);
 qla82xx_crb_addr_transform(EG);
 qla82xx_crb_addr_transform(MN);
 qla82xx_crb_addr_transform(MS);
 qla82xx_crb_addr_transform(CAS2);
 qla82xx_crb_addr_transform(CAS1);
 qla82xx_crb_addr_transform(CAS0);
 qla82xx_crb_addr_transform(CAM);
 qla82xx_crb_addr_transform(C2C1);
 qla82xx_crb_addr_transform(C2C0);
 qla82xx_crb_addr_transform(SMB);
 qla82xx_crb_addr_transform(OCM0);
 /*
 * Used only in P3 just define it for P2 also.
 */

 qla82xx_crb_addr_transform(I2C0);

 qla82xx_crb_table_initialized = 1;
}

static struct crb_128M_2M_block_map crb_128M_2M_map[64] = {
 {{{0, 0,         0,         0} } },
 {{{1, 0x0100000, 0x0102000, 0x120000},
 {1, 0x0110000, 0x0120000, 0x130000},
 {1, 0x0120000, 0x0122000, 0x124000},
 {1, 0x0130000, 0x0132000, 0x126000},
 {1, 0x0140000, 0x0142000, 0x128000},
 {1, 0x0150000, 0x0152000, 0x12a000},
 {1, 0x0160000, 0x0170000, 0x110000},
 {1, 0x0170000, 0x0172000, 0x12e000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {1, 0x01e0000, 0x01e0800, 0x122000},
 {0, 0x0000000, 0x0000000, 0x000000} } } ,
 {{{1, 0x0200000, 0x0210000, 0x180000} } },
 {{{0, 0,         0,         0} } },
 {{{1, 0x0400000, 0x0401000, 0x169000} } },
 {{{1, 0x0500000, 0x0510000, 0x140000} } },
 {{{1, 0x0600000, 0x0610000, 0x1c0000} } },
 {{{1, 0x0700000, 0x0704000, 0x1b8000} } },
 {{{1, 0x0800000, 0x0802000, 0x170000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {1, 0x08f0000, 0x08f2000, 0x172000} } },
 {{{1, 0x0900000, 0x0902000, 0x174000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {1, 0x09f0000, 0x09f2000, 0x176000} } },
 {{{0, 0x0a00000, 0x0a02000, 0x178000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {1, 0x0af0000, 0x0af2000, 0x17a000} } },
 {{{0, 0x0b00000, 0x0b02000, 0x17c000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {1, 0x0bf0000, 0x0bf2000, 0x17e000} } },
 {{{1, 0x0c00000, 0x0c04000, 0x1d4000} } },
 {{{1, 0x0d00000, 0x0d04000, 0x1a4000} } },
 {{{1, 0x0e00000, 0x0e04000, 0x1a0000} } },
 {{{1, 0x0f00000, 0x0f01000, 0x164000} } },
 {{{0, 0x1000000, 0x1004000, 0x1a8000} } },
 {{{1, 0x1100000, 0x1101000, 0x160000} } },
 {{{1, 0x1200000, 0x1201000, 0x161000} } },
 {{{1, 0x1300000, 0x1301000, 0x162000} } },
 {{{1, 0x1400000, 0x1401000, 0x163000} } },
 {{{1, 0x1500000, 0x1501000, 0x165000} } },
 {{{1, 0x1600000, 0x1601000, 0x166000} } },
 {{{0, 0,         0,         0} } },
 {{{0, 0,         0,         0} } },
 {{{0, 0,         0,         0} } },
 {{{0, 0,         0,         0} } },
 {{{0, 0,         0,         0} } },
 {{{0, 0,         0,         0} } },
 {{{1, 0x1d00000, 0x1d10000, 0x190000} } },
 {{{1, 0x1e00000, 0x1e01000, 0x16a000} } },
 {{{1, 0x1f00000, 0x1f10000, 0x150000} } },
 {{{0} } },
 {{{1, 0x2100000, 0x2102000, 0x120000},
 {1, 0x2110000, 0x2120000, 0x130000},
 {1, 0x2120000, 0x2122000, 0x124000},
 {1, 0x2130000, 0x2132000, 0x126000},
 {1, 0x2140000, 0x2142000, 0x128000},
 {1, 0x2150000, 0x2152000, 0x12a000},
 {1, 0x2160000, 0x2170000, 0x110000},
 {1, 0x2170000, 0x2172000, 0x12e000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000},
 {0, 0x0000000, 0x0000000, 0x000000} } },
 {{{1, 0x2200000, 0x2204000, 0x1b0000} } },
 {{{0} } },
 {{{0} } },
 {{{0} } },
 {{{0} } },
 {{{0} } },
 {{{1, 0x2800000, 0x2804000, 0x1a4000} } },
 {{{1, 0x2900000, 0x2901000, 0x16b000} } },
 {{{1, 0x2a00000, 0x2a00400, 0x1ac400} } },
 {{{1, 0x2b00000, 0x2b00400, 0x1ac800} } },
 {{{1, 0x2c00000, 0x2c00400, 0x1acc00} } },
 {{{1, 0x2d00000, 0x2d00400, 0x1ad000} } },
 {{{1, 0x2e00000, 0x2e00400, 0x1ad400} } },
 {{{1, 0x2f00000, 0x2f00400, 0x1ad800} } },
 {{{1, 0x3000000, 0x3000400, 0x1adc00} } },
 {{{0, 0x3100000, 0x3104000, 0x1a8000} } },
 {{{1, 0x3200000, 0x3204000, 0x1d4000} } },
 {{{1, 0x3300000, 0x3304000, 0x1a0000} } },
 {{{0} } },
 {{{1, 0x3500000, 0x3500400, 0x1ac000} } },
 {{{1, 0x3600000, 0x3600400, 0x1ae000} } },
 {{{1, 0x3700000, 0x3700400, 0x1ae400} } },
 {{{1, 0x3800000, 0x3804000, 0x1d0000} } },
 {{{1, 0x3900000, 0x3904000, 0x1b4000} } },
 {{{1, 0x3a00000, 0x3a04000, 0x1d8000} } },
 {{{0} } },
 {{{0} } },
 {{{1, 0x3d00000, 0x3d04000, 0x1dc000} } },
 {{{1, 0x3e00000, 0x3e01000, 0x167000} } },
 {{{1, 0x3f00000, 0x3f01000, 0x168000} } }
};

/*
 * top 12 bits of crb internal address (hub, agent)
 */

static unsigned qla82xx_crb_hub_agt[64] = {
 0,
 QLA82XX_HW_CRB_HUB_AGT_ADR_PS,
 QLA82XX_HW_CRB_HUB_AGT_ADR_MN,
 QLA82XX_HW_CRB_HUB_AGT_ADR_MS,
 0,
 QLA82XX_HW_CRB_HUB_AGT_ADR_SRE,
 QLA82XX_HW_CRB_HUB_AGT_ADR_NIU,
 QLA82XX_HW_CRB_HUB_AGT_ADR_QMN,
 QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0,
 QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1,
 QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2,
 QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3,
 QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q,
 QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR,
 QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB,
 QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4,
 QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA,
 QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0,
 QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1,
 QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2,
 QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3,
 QLA82XX_HW_CRB_HUB_AGT_ADR_PGND,
 QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI,
 QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0,
 QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1,
 QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2,
 QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3,
 0,
 QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI,
 QLA82XX_HW_CRB_HUB_AGT_ADR_SN,
 0,
 QLA82XX_HW_CRB_HUB_AGT_ADR_EG,
 0,
 QLA82XX_HW_CRB_HUB_AGT_ADR_PS,
 QLA82XX_HW_CRB_HUB_AGT_ADR_CAM,
 0,
 0,
 0,
 0,
 0,
 QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR,
 0,
 QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1,
 QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2,
 QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3,
 QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4,
 QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5,
 QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6,
 QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7,
 QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA,
 QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q,
 QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB,
 0,
 QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0,
 QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8,
 QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9,
 QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0,
 0,
 QLA82XX_HW_CRB_HUB_AGT_ADR_SMB,
 QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0,
 QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1,
 0,
 QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC,
 0,
};

/* Device states */
static const char *const q_dev_state[] = {
 [QLA8XXX_DEV_UNKNOWN]  = "Unknown",
 [QLA8XXX_DEV_COLD]  = "Cold/Re-init",
 [QLA8XXX_DEV_INITIALIZING] = "Initializing",
 [QLA8XXX_DEV_READY]  = "Ready",
 [QLA8XXX_DEV_NEED_RESET] = "Need Reset",
 [QLA8XXX_DEV_NEED_QUIESCENT] = "Need Quiescent",
 [QLA8XXX_DEV_FAILED]  = "Failed",
 [QLA8XXX_DEV_QUIESCENT]  = "Quiescent",
};

const char *qdev_state(uint32_t dev_state)
{
 return (dev_state < MAX_STATES) ? q_dev_state[dev_state] : "Unknown";
}

/*
 * In: 'off_in' is offset from CRB space in 128M pci map
 * Out: 'off_out' is 2M pci map addr
 * side effect: lock crb window
 */

static void
qla82xx_pci_set_crbwindow_2M(struct qla_hw_data *ha, ulong off_in,
        void __iomem **off_out)
{
 u32 win_read;
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 ha->crb_win = CRB_HI(off_in);
 writel(ha->crb_win, CRB_WINDOW_2M + ha->nx_pcibase);

 /* Read back value to make sure write has gone through before trying
 * to use it.
 */

 win_read = rd_reg_dword(CRB_WINDOW_2M + ha->nx_pcibase);
 if (win_read != ha->crb_win) {
  ql_dbg(ql_dbg_p3p, vha, 0xb000,
      "%s: Written crbwin (0x%x) "
      "!= Read crbwin (0x%x), off=0x%lx.\n",
      __func__, ha->crb_win, win_read, off_in);
 }
 *off_out = (off_in & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase;
}

static int
qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong off_in,
       void __iomem **off_out)
{
 struct crb_128M_2M_sub_block_map *m;

 if (off_in >= QLA82XX_CRB_MAX)
  return -1;

 if (off_in >= QLA82XX_PCI_CAMQM && off_in < QLA82XX_PCI_CAMQM_2M_END) {
  *off_out = (off_in - QLA82XX_PCI_CAMQM) +
      QLA82XX_PCI_CAMQM_2M_BASE + ha->nx_pcibase;
  return 0;
 }

 if (off_in < QLA82XX_PCI_CRBSPACE)
  return -1;

 off_in -= QLA82XX_PCI_CRBSPACE;

 /* Try direct map */
 m = &crb_128M_2M_map[CRB_BLK(off_in)].sub_block[CRB_SUBBLK(off_in)];

 if (m->valid && (m->start_128M <= off_in) && (m->end_128M > off_in)) {
  *off_out = off_in + m->start_2M - m->start_128M + ha->nx_pcibase;
  return 0;
 }
 /* Not in direct map, use crb window */
 *off_out = (void __iomem *)off_in;
 return 1;
}

#define CRB_WIN_LOCK_TIMEOUT 100000000
static int qla82xx_crb_win_lock(struct qla_hw_data *ha)
{
 int done = 0, timeout = 0;

 while (!done) {
  /* acquire semaphore3 from PCI HW block */
  done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK));
  if (done == 1)
   break;
  if (timeout >= CRB_WIN_LOCK_TIMEOUT)
   return -1;
  timeout++;
 }
 qla82xx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->portnum);
 return 0;
}

int
qla82xx_wr_32(struct qla_hw_data *ha, ulong off_in, u32 data)
{
 void __iomem *off;
 unsigned long flags = 0;
 int rv;

 rv = qla82xx_pci_get_crb_addr_2M(ha, off_in, &off);

 BUG_ON(rv == -1);

 if (rv == 1) {
#ifndef __CHECKER__
  write_lock_irqsave(&ha->hw_lock, flags);
#endif
  qla82xx_crb_win_lock(ha);
  qla82xx_pci_set_crbwindow_2M(ha, off_in, &off);
 }

 writel(data, (void __iomem *)off);

 if (rv == 1) {
  qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK));
#ifndef __CHECKER__
  write_unlock_irqrestore(&ha->hw_lock, flags);
#endif
 }
 return 0;
}

int
qla82xx_rd_32(struct qla_hw_data *ha, ulong off_in)
{
 void __iomem *off;
 unsigned long flags = 0;
 int rv;
 u32 data;

 rv = qla82xx_pci_get_crb_addr_2M(ha, off_in, &off);

 BUG_ON(rv == -1);

 if (rv == 1) {
#ifndef __CHECKER__
  write_lock_irqsave(&ha->hw_lock, flags);
#endif
  qla82xx_crb_win_lock(ha);
  qla82xx_pci_set_crbwindow_2M(ha, off_in, &off);
 }
 data = rd_reg_dword(off);

 if (rv == 1) {
  qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK));
#ifndef __CHECKER__
  write_unlock_irqrestore(&ha->hw_lock, flags);
#endif
 }
 return data;
}

/*
 * Context: task, might sleep
 */

int qla82xx_idc_lock(struct qla_hw_data *ha)
{
 const int delay_ms = 100, timeout_ms = 2000;
 int done, total = 0;

 might_sleep();

 while (true) {
  /* acquire semaphore5 from PCI HW block */
  done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_LOCK));
  if (done == 1)
   break;
  if (WARN_ON_ONCE(total >= timeout_ms))
   return -1;

  total += delay_ms;
  msleep(delay_ms);
 }

 return 0;
}

void qla82xx_idc_unlock(struct qla_hw_data *ha)
{
 qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_UNLOCK));
}

/*
 * check memory access boundary.
 * used by test agent. support ddr access only for now
 */

static unsigned long
qla82xx_pci_mem_bound_check(struct qla_hw_data *ha,
 unsigned long long addr, int size)
{
 if (!addr_in_range(addr, QLA82XX_ADDR_DDR_NET,
  QLA82XX_ADDR_DDR_NET_MAX) ||
  !addr_in_range(addr + size - 1, QLA82XX_ADDR_DDR_NET,
  QLA82XX_ADDR_DDR_NET_MAX) ||
  ((size != 1) && (size != 2) && (size != 4) && (size != 8)))
   return 0;
 else
  return 1;
}

static int qla82xx_pci_set_window_warning_count;

static unsigned long
qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
{
 int window;
 u32 win_read;
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 if (addr_in_range(addr, QLA82XX_ADDR_DDR_NET,
  QLA82XX_ADDR_DDR_NET_MAX)) {
  /* DDR network side */
  window = MN_WIN(addr);
  ha->ddr_mn_window = window;
  qla82xx_wr_32(ha,
   ha->mn_win_crb | QLA82XX_PCI_CRBSPACE, window);
  win_read = qla82xx_rd_32(ha,
   ha->mn_win_crb | QLA82XX_PCI_CRBSPACE);
  if ((win_read << 17) != window) {
   ql_dbg(ql_dbg_p3p, vha, 0xb003,
       "%s: Written MNwin (0x%x) != Read MNwin (0x%x).\n",
       __func__, window, win_read);
  }
  addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_DDR_NET;
 } else if (addr_in_range(addr, QLA82XX_ADDR_OCM0,
  QLA82XX_ADDR_OCM0_MAX)) {
  unsigned int temp1;

  if ((addr & 0x00ff800) == 0xff800) {
   ql_log(ql_log_warn, vha, 0xb004,
       "%s: QM access not handled.\n", __func__);
   addr = -1UL;
  }
  window = OCM_WIN(addr);
  ha->ddr_mn_window = window;
  qla82xx_wr_32(ha,
   ha->mn_win_crb | QLA82XX_PCI_CRBSPACE, window);
  win_read = qla82xx_rd_32(ha,
   ha->mn_win_crb | QLA82XX_PCI_CRBSPACE);
  temp1 = ((window & 0x1FF) << 7) |
      ((window & 0x0FFFE0000) >> 17);
  if (win_read != temp1) {
   ql_log(ql_log_warn, vha, 0xb005,
       "%s: Written OCMwin (0x%x) != Read OCMwin (0x%x).\n",
       __func__, temp1, win_read);
  }
  addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_OCM0_2M;

 } else if (addr_in_range(addr, QLA82XX_ADDR_QDR_NET,
  QLA82XX_P3_ADDR_QDR_NET_MAX)) {
  /* QDR network side */
  window = MS_WIN(addr);
  ha->qdr_sn_window = window;
  qla82xx_wr_32(ha,
   ha->ms_win_crb | QLA82XX_PCI_CRBSPACE, window);
  win_read = qla82xx_rd_32(ha,
   ha->ms_win_crb | QLA82XX_PCI_CRBSPACE);
  if (win_read != window) {
   ql_log(ql_log_warn, vha, 0xb006,
       "%s: Written MSwin (0x%x) != Read MSwin (0x%x).\n",
       __func__, window, win_read);
  }
  addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_QDR_NET;
 } else {
  /*
 * peg gdb frequently accesses memory that doesn't exist,
 * this limits the chit chat so debugging isn't slowed down.
 */

  if ((qla82xx_pci_set_window_warning_count++ < 8) ||
      (qla82xx_pci_set_window_warning_count%64 == 0)) {
   ql_log(ql_log_warn, vha, 0xb007,
       "%s: Warning:%s Unknown address range!.\n",
       __func__, QLA2XXX_DRIVER_NAME);
  }
  addr = -1UL;
 }
 return addr;
}

/* check if address is in the same windows as the previous access */
static int qla82xx_pci_is_same_window(struct qla_hw_data *ha,
 unsigned long long addr)
{
 int   window;
 unsigned long long qdr_max;

 qdr_max = QLA82XX_P3_ADDR_QDR_NET_MAX;

 /* DDR network side */
 if (addr_in_range(addr, QLA82XX_ADDR_DDR_NET,
  QLA82XX_ADDR_DDR_NET_MAX))
  BUG();
 else if (addr_in_range(addr, QLA82XX_ADDR_OCM0,
  QLA82XX_ADDR_OCM0_MAX))
  return 1;
 else if (addr_in_range(addr, QLA82XX_ADDR_OCM1,
  QLA82XX_ADDR_OCM1_MAX))
  return 1;
 else if (addr_in_range(addr, QLA82XX_ADDR_QDR_NET, qdr_max)) {
  /* QDR network side */
  window = ((addr - QLA82XX_ADDR_QDR_NET) >> 22) & 0x3f;
  if (ha->qdr_sn_window == window)
   return 1;
 }
 return 0;
}

static int qla82xx_pci_mem_read_direct(struct qla_hw_data *ha,
 u64 off, void *data, int size)
{
 unsigned long   flags;
 void __iomem *addr = NULL;
 int             ret = 0;
 u64             start;
 uint8_t __iomem  *mem_ptr = NULL;
 unsigned long   mem_base;
 unsigned long   mem_page;
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 write_lock_irqsave(&ha->hw_lock, flags);

 /*
 * If attempting to access unknown address or straddle hw windows,
 * do not access.
 */

 start = qla82xx_pci_set_window(ha, off);
 if ((start == -1UL) ||
  (qla82xx_pci_is_same_window(ha, off + size - 1) == 0)) {
  write_unlock_irqrestore(&ha->hw_lock, flags);
  ql_log(ql_log_fatal, vha, 0xb008,
      "%s out of bound pci memory "
      "access, offset is 0x%llx.\n",
      QLA2XXX_DRIVER_NAME, off);
  return -1;
 }

 write_unlock_irqrestore(&ha->hw_lock, flags);
 mem_base = pci_resource_start(ha->pdev, 0);
 mem_page = start & PAGE_MASK;
 /* Map two pages whenever user tries to access addresses in two
* consecutive pages.
*/

 if (mem_page != ((start + size - 1) & PAGE_MASK))
  mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2);
 else
  mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE);
 if (mem_ptr == NULL) {
  *(u8  *)data = 0;
  return -1;
 }
 addr = mem_ptr;
 addr += start & (PAGE_SIZE - 1);
 write_lock_irqsave(&ha->hw_lock, flags);

 switch (size) {
 case 1:
  *(u8  *)data = readb(addr);
  break;
 case 2:
  *(u16 *)data = readw(addr);
  break;
 case 4:
  *(u32 *)data = readl(addr);
  break;
 case 8:
  *(u64 *)data = readq(addr);
  break;
 default:
  ret = -1;
  break;
 }
 write_unlock_irqrestore(&ha->hw_lock, flags);

 if (mem_ptr)
  iounmap(mem_ptr);
 return ret;
}

static int
qla82xx_pci_mem_write_direct(struct qla_hw_data *ha,
 u64 off, void *data, int size)
{
 unsigned long   flags;
 void  __iomem *addr = NULL;
 int             ret = 0;
 u64             start;
 uint8_t __iomem *mem_ptr = NULL;
 unsigned long   mem_base;
 unsigned long   mem_page;
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 write_lock_irqsave(&ha->hw_lock, flags);

 /*
 * If attempting to access unknown address or straddle hw windows,
 * do not access.
 */

 start = qla82xx_pci_set_window(ha, off);
 if ((start == -1UL) ||
  (qla82xx_pci_is_same_window(ha, off + size - 1) == 0)) {
  write_unlock_irqrestore(&ha->hw_lock, flags);
  ql_log(ql_log_fatal, vha, 0xb009,
      "%s out of bound memory "
      "access, offset is 0x%llx.\n",
      QLA2XXX_DRIVER_NAME, off);
  return -1;
 }

 write_unlock_irqrestore(&ha->hw_lock, flags);
 mem_base = pci_resource_start(ha->pdev, 0);
 mem_page = start & PAGE_MASK;
 /* Map two pages whenever user tries to access addresses in two
 * consecutive pages.
 */

 if (mem_page != ((start + size - 1) & PAGE_MASK))
  mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE*2);
 else
  mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE);
 if (mem_ptr == NULL)
  return -1;

 addr = mem_ptr;
 addr += start & (PAGE_SIZE - 1);
 write_lock_irqsave(&ha->hw_lock, flags);

 switch (size) {
 case 1:
  writeb(*(u8  *)data, addr);
  break;
 case 2:
  writew(*(u16 *)data, addr);
  break;
 case 4:
  writel(*(u32 *)data, addr);
  break;
 case 8:
  writeq(*(u64 *)data, addr);
  break;
 default:
  ret = -1;
  break;
 }
 write_unlock_irqrestore(&ha->hw_lock, flags);
 if (mem_ptr)
  iounmap(mem_ptr);
 return ret;
}

#define MTU_FUDGE_FACTOR 100
static unsigned long
qla82xx_decode_crb_addr(unsigned long addr)
{
 int i;
 unsigned long base_addr, offset, pci_base;

 if (!qla82xx_crb_table_initialized)
  qla82xx_crb_addr_transform_setup();

 pci_base = ADDR_ERROR;
 base_addr = addr & 0xfff00000;
 offset = addr & 0x000fffff;

 for (i = 0; i < MAX_CRB_XFORM; i++) {
  if (crb_addr_xform[i] == base_addr) {
   pci_base = i << 20;
   break;
  }
 }
 if (pci_base == ADDR_ERROR)
  return pci_base;
 return pci_base + offset;
}

static long rom_max_timeout = 100;
static long qla82xx_rom_lock_timeout = 100;

static int
qla82xx_rom_lock(struct qla_hw_data *ha)
{
 int done = 0, timeout = 0;
 uint32_t lock_owner = 0;
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 while (!done) {
  /* acquire semaphore2 from PCI HW block */
  done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_LOCK));
  if (done == 1)
   break;
  if (timeout >= qla82xx_rom_lock_timeout) {
   lock_owner = qla82xx_rd_32(ha, QLA82XX_ROM_LOCK_ID);
   ql_dbg(ql_dbg_p3p, vha, 0xb157,
       "%s: Simultaneous flash access by following ports, active port = %d: accessing port = %d",
       __func__, ha->portnum, lock_owner);
   return -1;
  }
  timeout++;
 }
 qla82xx_wr_32(ha, QLA82XX_ROM_LOCK_ID, ha->portnum);
 return 0;
}

static void
qla82xx_rom_unlock(struct qla_hw_data *ha)
{
 qla82xx_wr_32(ha, QLA82XX_ROM_LOCK_ID, 0xffffffff);
 qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK));
}

static int
qla82xx_wait_rom_busy(struct qla_hw_data *ha)
{
 long timeout = 0;
 long done = 0 ;
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 while (done == 0) {
  done = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS);
  done &= 4;
  timeout++;
  if (timeout >= rom_max_timeout) {
   ql_dbg(ql_dbg_p3p, vha, 0xb00a,
       "%s: Timeout reached waiting for rom busy.\n",
       QLA2XXX_DRIVER_NAME);
   return -1;
  }
 }
 return 0;
}

static int
qla82xx_wait_rom_done(struct qla_hw_data *ha)
{
 long timeout = 0;
 long done = 0 ;
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 while (done == 0) {
  done = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS);
  done &= 2;
  timeout++;
  if (timeout >= rom_max_timeout) {
   ql_dbg(ql_dbg_p3p, vha, 0xb00b,
       "%s: Timeout reached waiting for rom done.\n",
       QLA2XXX_DRIVER_NAME);
   return -1;
  }
 }
 return 0;
}

static int
qla82xx_md_rw_32(struct qla_hw_data *ha, uint32_t off, u32 data, uint8_t flag)
{
 uint32_t  off_value, rval = 0;

 wrt_reg_dword(CRB_WINDOW_2M + ha->nx_pcibase, off & 0xFFFF0000);

 /* Read back value to make sure write has gone through */
 rd_reg_dword(CRB_WINDOW_2M + ha->nx_pcibase);
 off_value  = (off & 0x0000FFFF);

 if (flag)
  wrt_reg_dword(off_value + CRB_INDIRECT_2M + ha->nx_pcibase,
         data);
 else
  rval = rd_reg_dword(off_value + CRB_INDIRECT_2M +
        ha->nx_pcibase);

 return rval;
}

static int
qla82xx_do_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
{
 /* Dword reads to flash. */
 qla82xx_md_rw_32(ha, MD_DIRECT_ROM_WINDOW, (addr & 0xFFFF0000), 1);
 *valp = qla82xx_md_rw_32(ha, MD_DIRECT_ROM_READ_BASE +
     (addr & 0x0000FFFF), 0, 0);

 return 0;
}

static int
qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
{
 int ret, loops = 0;
 uint32_t lock_owner = 0;
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 while ((qla82xx_rom_lock(ha) != 0) && (loops < 50000)) {
  udelay(100);
  schedule();
  loops++;
 }
 if (loops >= 50000) {
  lock_owner = qla82xx_rd_32(ha, QLA82XX_ROM_LOCK_ID);
  ql_log(ql_log_fatal, vha, 0x00b9,
      "Failed to acquire SEM2 lock, Lock Owner %u.\n",
      lock_owner);
  return -1;
 }
 ret = qla82xx_do_rom_fast_read(ha, addr, valp);
 qla82xx_rom_unlock(ha);
 return ret;
}

static int
qla82xx_read_status_reg(struct qla_hw_data *ha, uint32_t *val)
{
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_RDSR);
 qla82xx_wait_rom_busy(ha);
 if (qla82xx_wait_rom_done(ha)) {
  ql_log(ql_log_warn, vha, 0xb00c,
      "Error waiting for rom done.\n");
  return -1;
 }
 *val = qla82xx_rd_32(ha, QLA82XX_ROMUSB_ROM_RDATA);
 return 0;
}

static int
qla82xx_flash_wait_write_finish(struct qla_hw_data *ha)
{
 uint32_t val = 0;
 int i, ret;
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0);
 for (i = 0; i < 50000; i++) {
  ret = qla82xx_read_status_reg(ha, &val);
  if (ret < 0 || (val & 1) == 0)
   return ret;
  udelay(10);
  cond_resched();
 }
 ql_log(ql_log_warn, vha, 0xb00d,
        "Timeout reached waiting for write finish.\n");
 return -1;
}

static int
qla82xx_flash_set_write_enable(struct qla_hw_data *ha)
{
 uint32_t val;

 qla82xx_wait_rom_busy(ha);
 qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0);
 qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WREN);
 qla82xx_wait_rom_busy(ha);
 if (qla82xx_wait_rom_done(ha))
  return -1;
 if (qla82xx_read_status_reg(ha, &val) != 0)
  return -1;
 if ((val & 2) != 2)
  return -1;
 return 0;
}

static int
qla82xx_write_status_reg(struct qla_hw_data *ha, uint32_t val)
{
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 if (qla82xx_flash_set_write_enable(ha))
  return -1;
 qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_WDATA, val);
 qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0x1);
 if (qla82xx_wait_rom_done(ha)) {
  ql_log(ql_log_warn, vha, 0xb00e,
      "Error waiting for rom done.\n");
  return -1;
 }
 return qla82xx_flash_wait_write_finish(ha);
}

static int
qla82xx_write_disable_flash(struct qla_hw_data *ha)
{
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WRDI);
 if (qla82xx_wait_rom_done(ha)) {
  ql_log(ql_log_warn, vha, 0xb00f,
      "Error waiting for rom done.\n");
  return -1;
 }
 return 0;
}

static int
ql82xx_rom_lock_d(struct qla_hw_data *ha)
{
 int loops = 0;
 uint32_t lock_owner = 0;
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 while ((qla82xx_rom_lock(ha) != 0) && (loops < 50000)) {
  udelay(100);
  cond_resched();
  loops++;
 }
 if (loops >= 50000) {
  lock_owner = qla82xx_rd_32(ha, QLA82XX_ROM_LOCK_ID);
  ql_log(ql_log_warn, vha, 0xb010,
      "ROM lock failed, Lock Owner %u.\n", lock_owner);
  return -1;
 }
 return 0;
}

static int
qla82xx_write_flash_dword(struct qla_hw_data *ha, uint32_t flashaddr,
 uint32_t data)
{
 int ret = 0;
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 ret = ql82xx_rom_lock_d(ha);
 if (ret < 0) {
  ql_log(ql_log_warn, vha, 0xb011,
      "ROM lock failed.\n");
  return ret;
 }

 ret = qla82xx_flash_set_write_enable(ha);
 if (ret < 0)
  goto done_write;

 qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_WDATA, data);
 qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, flashaddr);
 qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3);
 qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_PP);
 qla82xx_wait_rom_busy(ha);
 if (qla82xx_wait_rom_done(ha)) {
  ql_log(ql_log_warn, vha, 0xb012,
      "Error waiting for rom done.\n");
  ret = -1;
  goto done_write;
 }

 ret = qla82xx_flash_wait_write_finish(ha);

done_write:
 qla82xx_rom_unlock(ha);
 return ret;
}

/* This routine does CRB initialize sequence
 *  to put the ISP into operational state
 */

static int
qla82xx_pinit_from_rom(scsi_qla_host_t *vha)
{
 int addr, val;
 int i ;
 struct crb_addr_pair *buf;
 unsigned long off;
 unsigned offset, n;
 struct qla_hw_data *ha = vha->hw;

 /* Halt all the individual PEGs and other blocks of the ISP */
 qla82xx_rom_lock(ha);

 /* disable all I2Q */
 qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x10, 0x0);
 qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x14, 0x0);
 qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x18, 0x0);
 qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x1c, 0x0);
 qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x20, 0x0);
 qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x24, 0x0);

 /* disable all niu interrupts */
 qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x40, 0xff);
 /* disable xge rx/tx */
 qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x70000, 0x00);
 /* disable xg1 rx/tx */
 qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x80000, 0x00);
 /* disable sideband mac */
 qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x90000, 0x00);
 /* disable ap0 mac */
 qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0xa0000, 0x00);
 /* disable ap1 mac */
 qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0xb0000, 0x00);

 /* halt sre */
 val = qla82xx_rd_32(ha, QLA82XX_CRB_SRE + 0x1000);
 qla82xx_wr_32(ha, QLA82XX_CRB_SRE + 0x1000, val & (~(0x1)));

 /* halt epg */
 qla82xx_wr_32(ha, QLA82XX_CRB_EPG + 0x1300, 0x1);

 /* halt timers */
 qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x0, 0x0);
 qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x8, 0x0);
 qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x10, 0x0);
 qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x18, 0x0);
 qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x100, 0x0);
 qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x200, 0x0);

 /* halt pegs */
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x3c, 1);
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1 + 0x3c, 1);
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2 + 0x3c, 1);
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3 + 0x3c, 1);
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c, 1);
 msleep(20);

 /* big hammer */
 if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))
  /* don't reset CAM block on reset */
  qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff);
 else
  qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff);
 qla82xx_rom_unlock(ha);

 /* Read the signature value from the flash.
 * Offset 0: Contain signature (0xcafecafe)
 * Offset 4: Offset and number of addr/value pairs
 * that present in CRB initialize sequence
 */

 n = 0;
 if (qla82xx_rom_fast_read(ha, 0, &n) != 0 || n != 0xcafecafeUL ||
     qla82xx_rom_fast_read(ha, 4, &n) != 0) {
  ql_log(ql_log_fatal, vha, 0x006e,
      "Error Reading crb_init area: n: %08x.\n", n);
  return -1;
 }

 /* Offset in flash = lower 16 bits
 * Number of entries = upper 16 bits
 */

 offset = n & 0xffffU;
 n = (n >> 16) & 0xffffU;

 /* number of addr/value pair should not exceed 1024 entries */
 if (n  >= 1024) {
  ql_log(ql_log_fatal, vha, 0x0071,
      "Card flash not initialized:n=0x%x.\n", n);
  return -1;
 }

 ql_log(ql_log_info, vha, 0x0072,
     "%d CRB init values found in ROM.\n", n);

 buf = kmalloc_array(n, sizeof(struct crb_addr_pair), GFP_KERNEL);
 if (buf == NULL) {
  ql_log(ql_log_fatal, vha, 0x010c,
      "Unable to allocate memory.\n");
  return -ENOMEM;
 }

 for (i = 0; i < n; i++) {
  if (qla82xx_rom_fast_read(ha, 8*i + 4*offset, &val) != 0 ||
      qla82xx_rom_fast_read(ha, 8*i + 4*offset + 4, &addr) != 0) {
   kfree(buf);
   return -1;
  }

  buf[i].addr = addr;
  buf[i].data = val;
 }

 for (i = 0; i < n; i++) {
  /* Translate internal CRB initialization
 * address to PCI bus address
 */

  off = qla82xx_decode_crb_addr((unsigned long)buf[i].addr) +
      QLA82XX_PCI_CRBSPACE;
  /* Not all CRB  addr/value pair to be written,
 * some of them are skipped
 */


  /* skipping cold reboot MAGIC */
  if (off == QLA82XX_CAM_RAM(0x1fc))
   continue;

  /* do not reset PCI */
  if (off == (ROMUSB_GLB + 0xbc))
   continue;

  /* skip core clock, so that firmware can increase the clock */
  if (off == (ROMUSB_GLB + 0xc8))
   continue;

  /* skip the function enable register */
  if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION))
   continue;

  if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION2))
   continue;

  if ((off & 0x0ff00000) == QLA82XX_CRB_SMB)
   continue;

  if ((off & 0x0ff00000) == QLA82XX_CRB_DDR_NET)
   continue;

  if (off == ADDR_ERROR) {
   ql_log(ql_log_fatal, vha, 0x0116,
       "Unknown addr: 0x%08lx.\n", buf[i].addr);
   continue;
  }

  qla82xx_wr_32(ha, off, buf[i].data);

  /* ISP requires much bigger delay to settle down,
 * else crb_window returns 0xffffffff
 */

  if (off == QLA82XX_ROMUSB_GLB_SW_RESET)
   msleep(1000);

  /* ISP requires millisec delay between
 * successive CRB register updation
 */

  msleep(1);
 }

 kfree(buf);

 /* Resetting the data and instruction cache */
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0xec, 0x1e);
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0x4c, 8);
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_I+0x4c, 8);

 /* Clear all protocol processing engines */
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0x8, 0);
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0xc, 0);
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0x8, 0);
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0xc, 0);
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0x8, 0);
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0xc, 0);
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0x8, 0);
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0xc, 0);
 return 0;
}

static int
qla82xx_pci_mem_write_2M(struct qla_hw_data *ha,
  u64 off, void *data, int size)
{
 int i, j, ret = 0, loop, sz[2], off0;
 int scale, shift_amount, startword;
 uint32_t temp;
 uint64_t off8, mem_crb, tmpw, word[2] = {0, 0};

 /*
 * If not MN, go check for MS or invalid.
 */

 if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
  mem_crb = QLA82XX_CRB_QDR_NET;
 else {
  mem_crb = QLA82XX_CRB_DDR_NET;
  if (qla82xx_pci_mem_bound_check(ha, off, size) == 0)
   return qla82xx_pci_mem_write_direct(ha,
       off, data, size);
 }

 off0 = off & 0x7;
 sz[0] = (size < (8 - off0)) ? size : (8 - off0);
 sz[1] = size - sz[0];

 off8 = off & 0xfffffff0;
 loop = (((off & 0xf) + size - 1) >> 4) + 1;
 shift_amount = 4;
 scale = 2;
 startword = (off & 0xf)/8;

 for (i = 0; i < loop; i++) {
  if (qla82xx_pci_mem_read_2M(ha, off8 +
      (i << shift_amount), &word[i * scale], 8))
   return -1;
 }

 switch (size) {
 case 1:
  tmpw = *((uint8_t *)data);
  break;
 case 2:
  tmpw = *((uint16_t *)data);
  break;
 case 4:
  tmpw = *((uint32_t *)data);
  break;
 case 8:
 default:
  tmpw = *((uint64_t *)data);
  break;
 }

 if (sz[0] == 8) {
  word[startword] = tmpw;
 } else {
  word[startword] &=
   ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
  word[startword] |= tmpw << (off0 * 8);
 }
 if (sz[1] != 0) {
  word[startword+1] &= ~(~0ULL << (sz[1] * 8));
  word[startword+1] |= tmpw >> (sz[0] * 8);
 }

 for (i = 0; i < loop; i++) {
  temp = off8 + (i << shift_amount);
  qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp);
  temp = 0;
  qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp);
  temp = word[i * scale] & 0xffffffff;
  qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp);
  temp = (word[i * scale] >> 32) & 0xffffffff;
  qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp);
  temp = word[i*scale + 1] & 0xffffffff;
  qla82xx_wr_32(ha, mem_crb +
      MIU_TEST_AGT_WRDATA_UPPER_LO, temp);
  temp = (word[i*scale + 1] >> 32) & 0xffffffff;
  qla82xx_wr_32(ha, mem_crb +
      MIU_TEST_AGT_WRDATA_UPPER_HI, temp);

  temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
  qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
  temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
  qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);

  for (j = 0; j < MAX_CTL_CHECK; j++) {
   temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
   if ((temp & MIU_TA_CTL_BUSY) == 0)
    break;
  }

  if (j >= MAX_CTL_CHECK) {
   if (printk_ratelimit())
    dev_err(&ha->pdev->dev,
        "failed to write through agent.\n");
   ret = -1;
   break;
  }
 }

 return ret;
}

static int
qla82xx_fw_load_from_flash(struct qla_hw_data *ha)
{
 int  i;
 long size = 0;
 long flashaddr = ha->flt_region_bootload << 2;
 long memaddr = BOOTLD_START;
 u64 data;
 u32 high, low;

 size = (IMAGE_START - BOOTLD_START) / 8;

 for (i = 0; i < size; i++) {
  if ((qla82xx_rom_fast_read(ha, flashaddr, (int *)&low)) ||
      (qla82xx_rom_fast_read(ha, flashaddr + 4, (int *)&high))) {
   return -1;
  }
  data = ((u64)high << 32) | low ;
  qla82xx_pci_mem_write_2M(ha, memaddr, &data, 8);
  flashaddr += 8;
  memaddr += 8;

  if (i % 0x1000 == 0)
   msleep(1);
 }
 udelay(100);
 read_lock(&ha->hw_lock);
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
 qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
 read_unlock(&ha->hw_lock);
 return 0;
}

int
qla82xx_pci_mem_read_2M(struct qla_hw_data *ha,
  u64 off, void *data, int size)
{
 int i, j = 0, k, start, end, loop, sz[2], off0[2];
 int       shift_amount;
 uint32_t      temp;
 uint64_t      off8, val, mem_crb, word[2] = {0, 0};

 /*
 * If not MN, go check for MS or invalid.
 */


 if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
  mem_crb = QLA82XX_CRB_QDR_NET;
 else {
  mem_crb = QLA82XX_CRB_DDR_NET;
  if (qla82xx_pci_mem_bound_check(ha, off, size) == 0)
   return qla82xx_pci_mem_read_direct(ha,
       off, data, size);
 }

 off8 = off & 0xfffffff0;
 off0[0] = off & 0xf;
 sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]);
 shift_amount = 4;
 loop = ((off0[0] + size - 1) >> shift_amount) + 1;
 off0[1] = 0;
 sz[1] = size - sz[0];

 for (i = 0; i < loop; i++) {
  temp = off8 + (i << shift_amount);
  qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp);
  temp = 0;
  qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_HI, temp);
  temp = MIU_TA_CTL_ENABLE;
  qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
  temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE;
  qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);

  for (j = 0; j < MAX_CTL_CHECK; j++) {
   temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
   if ((temp & MIU_TA_CTL_BUSY) == 0)
    break;
  }

  if (j >= MAX_CTL_CHECK) {
   if (printk_ratelimit())
    dev_err(&ha->pdev->dev,
        "failed to read through agent.\n");
   break;
  }

  start = off0[i] >> 2;
  end   = (off0[i] + sz[i] - 1) >> 2;
  for (k = start; k <= end; k++) {
   temp = qla82xx_rd_32(ha,
     mem_crb + MIU_TEST_AGT_RDDATA(k));
   word[i] |= ((uint64_t)temp << (32 * (k & 1)));
  }
 }

 if (j >= MAX_CTL_CHECK)
  return -1;

 if ((off0[0] & 7) == 0) {
  val = word[0];
 } else {
  val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) |
   ((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8));
 }

 switch (size) {
 case 1:
  *(uint8_t  *)data = val;
  break;
 case 2:
  *(uint16_t *)data = val;
  break;
 case 4:
  *(uint32_t *)data = val;
  break;
 case 8:
  *(uint64_t *)data = val;
  break;
 }
 return 0;
}


static struct qla82xx_uri_table_desc *
qla82xx_get_table_desc(const u8 *unirom, int section)
{
 uint32_t i;
 struct qla82xx_uri_table_desc *directory =
  (struct qla82xx_uri_table_desc *)&unirom[0];
 uint32_t offset;
 uint32_t tab_type;
 uint32_t entries = le32_to_cpu(directory->num_entries);

 for (i = 0; i < entries; i++) {
  offset = le32_to_cpu(directory->findex) +
      (i * le32_to_cpu(directory->entry_size));
  tab_type = get_unaligned_le32((u32 *)&unirom[offset] + 8);

  if (tab_type == section)
   return (struct qla82xx_uri_table_desc *)&unirom[offset];
 }

 return NULL;
}

static struct qla82xx_uri_data_desc *
qla82xx_get_data_desc(struct qla_hw_data *ha,
 u32 section, u32 idx_offset)
{
 const u8 *unirom = ha->hablob->fw->data;
 int idx = get_unaligned_le32((u32 *)&unirom[ha->file_prd_off] +
         idx_offset);
 struct qla82xx_uri_table_desc *tab_desc = NULL;
 uint32_t offset;

 tab_desc = qla82xx_get_table_desc(unirom, section);
 if (!tab_desc)
  return NULL;

 offset = le32_to_cpu(tab_desc->findex) +
     (le32_to_cpu(tab_desc->entry_size) * idx);

 return (struct qla82xx_uri_data_desc *)&unirom[offset];
}

static u8 *
qla82xx_get_bootld_offset(struct qla_hw_data *ha)
{
 u32 offset = BOOTLD_START;
 struct qla82xx_uri_data_desc *uri_desc = NULL;

 if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
  uri_desc = qla82xx_get_data_desc(ha,
      QLA82XX_URI_DIR_SECT_BOOTLD, QLA82XX_URI_BOOTLD_IDX_OFF);
  if (uri_desc)
   offset = le32_to_cpu(uri_desc->findex);
 }

 return (u8 *)&ha->hablob->fw->data[offset];
}

static u32 qla82xx_get_fw_size(struct qla_hw_data *ha)
{
 struct qla82xx_uri_data_desc *uri_desc = NULL;

 if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
  uri_desc =  qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW,
      QLA82XX_URI_FIRMWARE_IDX_OFF);
  if (uri_desc)
   return le32_to_cpu(uri_desc->size);
 }

 return get_unaligned_le32(&ha->hablob->fw->data[FW_SIZE_OFFSET]);
}

static u8 *
qla82xx_get_fw_offs(struct qla_hw_data *ha)
{
 u32 offset = IMAGE_START;
 struct qla82xx_uri_data_desc *uri_desc = NULL;

 if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
  uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW,
   QLA82XX_URI_FIRMWARE_IDX_OFF);
  if (uri_desc)
   offset = le32_to_cpu(uri_desc->findex);
 }

 return (u8 *)&ha->hablob->fw->data[offset];
}

int
qla82xx_iospace_config(struct qla_hw_data *ha)
{
 uint32_t len = 0;

 if (pci_request_regions(ha->pdev, QLA2XXX_DRIVER_NAME)) {
  ql_log_pci(ql_log_fatal, ha->pdev, 0x000c,
      "Failed to reserver selected regions.\n");
  goto iospace_error_exit;
 }

 /* Use MMIO operations for all accesses. */
 if (!(pci_resource_flags(ha->pdev, 0) & IORESOURCE_MEM)) {
  ql_log_pci(ql_log_fatal, ha->pdev, 0x000d,
      "Region #0 not an MMIO resource, aborting.\n");
  goto iospace_error_exit;
 }

 len = pci_resource_len(ha->pdev, 0);
 ha->nx_pcibase = ioremap(pci_resource_start(ha->pdev, 0), len);
 if (!ha->nx_pcibase) {
  ql_log_pci(ql_log_fatal, ha->pdev, 0x000e,
      "Cannot remap pcibase MMIO, aborting.\n");
  goto iospace_error_exit;
 }

 /* Mapping of IO base pointer */
 if (IS_QLA8044(ha)) {
  ha->iobase = ha->nx_pcibase;
 } else if (IS_QLA82XX(ha)) {
  ha->iobase = ha->nx_pcibase + 0xbc000 + (ha->pdev->devfn << 11);
 }

 if (!ql2xdbwr) {
  ha->nxdb_wr_ptr = ioremap((pci_resource_start(ha->pdev, 4) +
      (ha->pdev->devfn << 12)), 4);
  if (!ha->nxdb_wr_ptr) {
   ql_log_pci(ql_log_fatal, ha->pdev, 0x000f,
       "Cannot remap MMIO, aborting.\n");
   goto iospace_error_exit;
  }

  /* Mapping of IO base pointer,
 * door bell read and write pointer
 */

  ha->nxdb_rd_ptr = ha->nx_pcibase + (512 * 1024) +
      (ha->pdev->devfn * 8);
 } else {
  ha->nxdb_wr_ptr = (void __iomem *)(ha->pdev->devfn == 6 ?
   QLA82XX_CAMRAM_DB1 :
   QLA82XX_CAMRAM_DB2);
 }

 ha->max_req_queues = ha->max_rsp_queues = 1;
 ha->msix_count = ha->max_rsp_queues + 1;
 ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc006,
     "nx_pci_base=%p iobase=%p "
     "max_req_queues=%d msix_count=%d.\n",
     ha->nx_pcibase, ha->iobase,
     ha->max_req_queues, ha->msix_count);
 ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0010,
     "nx_pci_base=%p iobase=%p "
     "max_req_queues=%d msix_count=%d.\n",
     ha->nx_pcibase, ha->iobase,
     ha->max_req_queues, ha->msix_count);
 return 0;

iospace_error_exit:
 return -ENOMEM;
}

/* GS related functions */

/* Initialization related functions */

/**
 * qla82xx_pci_config() - Setup ISP82xx PCI configuration registers.
 * @vha: HA context
 *
 * Returns 0 on success.
*/

int
qla82xx_pci_config(scsi_qla_host_t *vha)
{
 struct qla_hw_data *ha = vha->hw;
 int ret;

 pci_set_master(ha->pdev);
 ret = pci_set_mwi(ha->pdev);
 ha->chip_revision = ha->pdev->revision;
 ql_dbg(ql_dbg_init, vha, 0x0043,
     "Chip revision:%d; pci_set_mwi() returned %d.\n",
     ha->chip_revision, ret);
 return 0;
}

/**
 * qla82xx_reset_chip() - Setup ISP82xx PCI configuration registers.
 * @vha: HA context
 *
 * Returns 0 on success.
 */

int
qla82xx_reset_chip(scsi_qla_host_t *vha)
{
 struct qla_hw_data *ha = vha->hw;

 ha->isp_ops->disable_intrs(ha);

 return QLA_SUCCESS;
}

void qla82xx_config_rings(struct scsi_qla_host *vha)
{
 struct qla_hw_data *ha = vha->hw;
 struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;
 struct init_cb_81xx *icb;
 struct req_que *req = ha->req_q_map[0];
 struct rsp_que *rsp = ha->rsp_q_map[0];

 /* Setup ring parameters in initialization control block. */
 icb = (struct init_cb_81xx *)ha->init_cb;
 icb->request_q_outpointer = cpu_to_le16(0);
 icb->response_q_inpointer = cpu_to_le16(0);
 icb->request_q_length = cpu_to_le16(req->length);
 icb->response_q_length = cpu_to_le16(rsp->length);
 put_unaligned_le64(req->dma, &icb->request_q_address);
 put_unaligned_le64(rsp->dma, &icb->response_q_address);

 wrt_reg_dword(®->req_q_out[0], 0);
 wrt_reg_dword(®->rsp_q_in[0], 0);
 wrt_reg_dword(®->rsp_q_out[0], 0);
}

static int
qla82xx_fw_load_from_blob(struct qla_hw_data *ha)
{
 u64 *ptr64;
 u32 i, flashaddr, size;
 __le64 data;

 size = (IMAGE_START - BOOTLD_START) / 8;

 ptr64 = (u64 *)qla82xx_get_bootld_offset(ha);
 flashaddr = BOOTLD_START;

 for (i = 0; i < size; i++) {
  data = cpu_to_le64(ptr64[i]);
  if (qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8))
   return -EIO;
  flashaddr += 8;
 }

 flashaddr = FLASH_ADDR_START;
 size = qla82xx_get_fw_size(ha) / 8;
 ptr64 = (u64 *)qla82xx_get_fw_offs(ha);

 for (i = 0; i < size; i++) {
  data = cpu_to_le64(ptr64[i]);

  if (qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8))
   return -EIO;
  flashaddr += 8;
 }
 udelay(100);

 /* Write a magic value to CAMRAM register
 * at a specified offset to indicate
 * that all data is written and
 * ready for firmware to initialize.
 */

 qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), QLA82XX_BDINFO_MAGIC);

 read_lock(&ha->hw_lock);
 qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
 qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
 read_unlock(&ha->hw_lock);
 return 0;
}

static int
qla82xx_set_product_offset(struct qla_hw_data *ha)
{
 struct qla82xx_uri_table_desc *ptab_desc = NULL;
 const uint8_t *unirom = ha->hablob->fw->data;
 uint32_t i;
 uint32_t entries;
 uint32_t flags, file_chiprev, offset;
 uint8_t chiprev = ha->chip_revision;
 /* Hardcoding mn_present flag for P3P */
 int mn_present = 0;
 uint32_t flagbit;

 ptab_desc = qla82xx_get_table_desc(unirom,
   QLA82XX_URI_DIR_SECT_PRODUCT_TBL);
 if (!ptab_desc)
  return -1;

 entries = le32_to_cpu(ptab_desc->num_entries);

 for (i = 0; i < entries; i++) {
  offset = le32_to_cpu(ptab_desc->findex) +
   (i * le32_to_cpu(ptab_desc->entry_size));
  flags = le32_to_cpu(*((__le32 *)&unirom[offset] +
   QLA82XX_URI_FLAGS_OFF));
  file_chiprev = le32_to_cpu(*((__le32 *)&unirom[offset] +
   QLA82XX_URI_CHIP_REV_OFF));

  flagbit = mn_present ? 1 : 2;

  if ((chiprev == file_chiprev) && ((1ULL << flagbit) & flags)) {
   ha->file_prd_off = offset;
   return 0;
  }
 }
 return -1;
}

static int
qla82xx_validate_firmware_blob(scsi_qla_host_t *vha, uint8_t fw_type)
{
 uint32_t val;
 uint32_t min_size;
 struct qla_hw_data *ha = vha->hw;
 const struct firmware *fw = ha->hablob->fw;

 ha->fw_type = fw_type;

 if (fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
  if (qla82xx_set_product_offset(ha))
   return -EINVAL;

  min_size = QLA82XX_URI_FW_MIN_SIZE;
 } else {
  val = get_unaligned_le32(&fw->data[QLA82XX_FW_MAGIC_OFFSET]);
  if (val != QLA82XX_BDINFO_MAGIC)
   return -EINVAL;

  min_size = QLA82XX_FW_MIN_SIZE;
 }

 if (fw->size < min_size)
  return -EINVAL;
 return 0;
}

static int
qla82xx_check_cmdpeg_state(struct qla_hw_data *ha)
{
 u32 val = 0;
 int retries = 60;
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 do {
  read_lock(&ha->hw_lock);
  val = qla82xx_rd_32(ha, CRB_CMDPEG_STATE);
  read_unlock(&ha->hw_lock);

  switch (val) {
  case PHAN_INITIALIZE_COMPLETE:
  case PHAN_INITIALIZE_ACK:
   return QLA_SUCCESS;
  case PHAN_INITIALIZE_FAILED:
   break;
  default:
   break;
  }
  ql_log(ql_log_info, vha, 0x00a8,
      "CRB_CMDPEG_STATE: 0x%x and retries:0x%x.\n",
      val, retries);

  msleep(500);

 } while (--retries);

 ql_log(ql_log_fatal, vha, 0x00a9,
     "Cmd Peg initialization failed: 0x%x.\n", val);

 val = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_PEGTUNE_DONE);
 read_lock(&ha->hw_lock);
 qla82xx_wr_32(ha, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
 read_unlock(&ha->hw_lock);
 return QLA_FUNCTION_FAILED;
}

static int
qla82xx_check_rcvpeg_state(struct qla_hw_data *ha)
{
 u32 val = 0;
 int retries = 60;
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 do {
  read_lock(&ha->hw_lock);
  val = qla82xx_rd_32(ha, CRB_RCVPEG_STATE);
  read_unlock(&ha->hw_lock);

  switch (val) {
  case PHAN_INITIALIZE_COMPLETE:
  case PHAN_INITIALIZE_ACK:
   return QLA_SUCCESS;
  case PHAN_INITIALIZE_FAILED:
   break;
  default:
   break;
  }
  ql_log(ql_log_info, vha, 0x00ab,
      "CRB_RCVPEG_STATE: 0x%x and retries: 0x%x.\n",
      val, retries);

  msleep(500);

 } while (--retries);

 ql_log(ql_log_fatal, vha, 0x00ac,
     "Rcv Peg initialization failed: 0x%x.\n", val);
 read_lock(&ha->hw_lock);
 qla82xx_wr_32(ha, CRB_RCVPEG_STATE, PHAN_INITIALIZE_FAILED);
 read_unlock(&ha->hw_lock);
 return QLA_FUNCTION_FAILED;
}

/* ISR related functions */
static struct qla82xx_legacy_intr_set legacy_intr[] =
 QLA82XX_LEGACY_INTR_CONFIG;

/*
 * qla82xx_mbx_completion() - Process mailbox command completions.
 * @ha: SCSI driver HA context
 * @mb0: Mailbox0 register
 */

void
qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
{
 uint16_t cnt;
 __le16 __iomem *wptr;
 struct qla_hw_data *ha = vha->hw;
 struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;

 wptr = ®->mailbox_out[1];

 /* Load return mailbox registers. */
 ha->flags.mbox_int = 1;
 ha->mailbox_out[0] = mb0;

 for (cnt = 1; cnt < ha->mbx_count; cnt++) {
  ha->mailbox_out[cnt] = rd_reg_word(wptr);
  wptr++;
 }

 if (!ha->mcp)
  ql_dbg(ql_dbg_async, vha, 0x5053,
      "MBX pointer ERROR.\n");
}

/**
 * qla82xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
 * @irq: interrupt number
 * @dev_id: SCSI driver HA context
 *
 * Called by system whenever the host adapter generates an interrupt.
 *
 * Returns handled flag.
 */

irqreturn_t
qla82xx_intr_handler(int irq, void *dev_id)
{
 scsi_qla_host_t *vha;
 struct qla_hw_data *ha;
 struct rsp_que *rsp;
 struct device_reg_82xx __iomem *reg;
 int status = 0, status1 = 0;
 unsigned long flags;
 unsigned long iter;
 uint32_t stat = 0;
 uint16_t mb[8];

 rsp = (struct rsp_que *) dev_id;
 if (!rsp) {
  ql_log(ql_log_info, NULL, 0xb053,
      "%s: NULL response queue pointer.\n", __func__);
  return IRQ_NONE;
 }
 ha = rsp->hw;

 if (!ha->flags.msi_enabled) {
  status = qla82xx_rd_32(ha, ISR_INT_VECTOR);
  if (!(status & ha->nx_legacy_intr.int_vec_bit))
   return IRQ_NONE;

  status1 = qla82xx_rd_32(ha, ISR_INT_STATE_REG);
  if (!ISR_IS_LEGACY_INTR_TRIGGERED(status1))
   return IRQ_NONE;
 }

 /* clear the interrupt */
 qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff);

 /* read twice to ensure write is flushed */
 qla82xx_rd_32(ha, ISR_INT_VECTOR);
 qla82xx_rd_32(ha, ISR_INT_VECTOR);

 reg = &ha->iobase->isp82;

 spin_lock_irqsave(&ha->hardware_lock, flags);
 vha = pci_get_drvdata(ha->pdev);
 for (iter = 1; iter--; ) {

  if (rd_reg_dword(®->host_int)) {
   stat = rd_reg_dword(®->host_status);

   switch (stat & 0xff) {
   case 0x1:
   case 0x2:
   case 0x10:
   case 0x11:
    qla82xx_mbx_completion(vha, MSW(stat));
    status |= MBX_INTERRUPT;
    break;
   case 0x12:
    mb[0] = MSW(stat);
    mb[1] = rd_reg_word(®->mailbox_out[1]);
    mb[2] = rd_reg_word(®->mailbox_out[2]);
    mb[3] = rd_reg_word(®->mailbox_out[3]);
    qla2x00_async_event(vha, rsp, mb);
    break;
   case 0x13:
    qla24xx_process_response_queue(vha, rsp);
    break;
   default:
    ql_dbg(ql_dbg_async, vha, 0x5054,
        "Unrecognized interrupt type (%d).\n",
        stat & 0xff);
    break;
   }
  }
  wrt_reg_dword(®->host_int, 0);
 }

 qla2x00_handle_mbx_completion(ha, status);
 spin_unlock_irqrestore(&ha->hardware_lock, flags);

 if (!ha->flags.msi_enabled)
  qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);

 return IRQ_HANDLED;
}

irqreturn_t
qla82xx_msix_default(int irq, void *dev_id)
{
 scsi_qla_host_t *vha;
 struct qla_hw_data *ha;
 struct rsp_que *rsp;
 struct device_reg_82xx __iomem *reg;
 int status = 0;
 unsigned long flags;
 uint32_t stat = 0;
 uint32_t host_int = 0;
 uint16_t mb[8];

 rsp = (struct rsp_que *) dev_id;
 if (!rsp) {
  printk(KERN_INFO
   "%s(): NULL response queue pointer.\n", __func__);
  return IRQ_NONE;
 }
 ha = rsp->hw;

 reg = &ha->iobase->isp82;

 spin_lock_irqsave(&ha->hardware_lock, flags);
 vha = pci_get_drvdata(ha->pdev);
 do {
  host_int = rd_reg_dword(®->host_int);
  if (qla2x00_check_reg32_for_disconnect(vha, host_int))
   break;
  if (host_int) {
   stat = rd_reg_dword(®->host_status);

   switch (stat & 0xff) {
   case 0x1:
   case 0x2:
   case 0x10:
   case 0x11:
    qla82xx_mbx_completion(vha, MSW(stat));
    status |= MBX_INTERRUPT;
    break;
   case 0x12:
    mb[0] = MSW(stat);
    mb[1] = rd_reg_word(®->mailbox_out[1]);
    mb[2] = rd_reg_word(®->mailbox_out[2]);
    mb[3] = rd_reg_word(®->mailbox_out[3]);
    qla2x00_async_event(vha, rsp, mb);
    break;
   case 0x13:
    qla24xx_process_response_queue(vha, rsp);
    break;
   default:
    ql_dbg(ql_dbg_async, vha, 0x5041,
        "Unrecognized interrupt type (%d).\n",
        stat & 0xff);
    break;
   }
  }
  wrt_reg_dword(®->host_int, 0);
 } while (0);

 qla2x00_handle_mbx_completion(ha, status);
 spin_unlock_irqrestore(&ha->hardware_lock, flags);

 return IRQ_HANDLED;
}

irqreturn_t
qla82xx_msix_rsp_q(int irq, void *dev_id)
{
 scsi_qla_host_t *vha;
 struct qla_hw_data *ha;
 struct rsp_que *rsp;
 struct device_reg_82xx __iomem *reg;
 unsigned long flags;
 uint32_t host_int = 0;

 rsp = (struct rsp_que *) dev_id;
 if (!rsp) {
  printk(KERN_INFO
   "%s(): NULL response queue pointer.\n", __func__);
  return IRQ_NONE;
 }

 ha = rsp->hw;
 reg = &ha->iobase->isp82;
 spin_lock_irqsave(&ha->hardware_lock, flags);
 vha = pci_get_drvdata(ha->pdev);
 host_int = rd_reg_dword(®->host_int);
 if (qla2x00_check_reg32_for_disconnect(vha, host_int))
  goto out;
 qla24xx_process_response_queue(vha, rsp);
 wrt_reg_dword(®->host_int, 0);
out:
 spin_unlock_irqrestore(&ha->hardware_lock, flags);
 return IRQ_HANDLED;
}

void
qla82xx_poll(int irq, void *dev_id)
{
 scsi_qla_host_t *vha;
 struct qla_hw_data *ha;
 struct rsp_que *rsp;
 struct device_reg_82xx __iomem *reg;
 uint32_t stat;
 uint32_t host_int = 0;
 uint16_t mb[8];
 unsigned long flags;

 rsp = (struct rsp_que *) dev_id;
 if (!rsp) {
  printk(KERN_INFO
   "%s(): NULL response queue pointer.\n", __func__);
  return;
 }
 ha = rsp->hw;

 reg = &ha->iobase->isp82;
 spin_lock_irqsave(&ha->hardware_lock, flags);
 vha = pci_get_drvdata(ha->pdev);

 host_int = rd_reg_dword(®->host_int);
 if (qla2x00_check_reg32_for_disconnect(vha, host_int))
  goto out;
 if (host_int) {
  stat = rd_reg_dword(®->host_status);
  switch (stat & 0xff) {
  case 0x1:
  case 0x2:
  case 0x10:
  case 0x11:
   qla82xx_mbx_completion(vha, MSW(stat));
   break;
  case 0x12:
   mb[0] = MSW(stat);
   mb[1] = rd_reg_word(®->mailbox_out[1]);
   mb[2] = rd_reg_word(®->mailbox_out[2]);
   mb[3] = rd_reg_word(®->mailbox_out[3]);
   qla2x00_async_event(vha, rsp, mb);
   break;
  case 0x13:
   qla24xx_process_response_queue(vha, rsp);
   break;
  default:
   ql_dbg(ql_dbg_p3p, vha, 0xb013,
       "Unrecognized interrupt type (%d).\n",
       stat * 0xff);
   break;
  }
  wrt_reg_dword(®->host_int, 0);
 }
out:
 spin_unlock_irqrestore(&ha->hardware_lock, flags);
}

void
qla82xx_enable_intrs(struct qla_hw_data *ha)
{
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 qla82xx_mbx_intr_enable(vha);
 spin_lock_irq(&ha->hardware_lock);
 if (IS_QLA8044(ha))
  qla8044_wr_reg(ha, LEG_INTR_MASK_OFFSET, 0);
 else
  qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
 spin_unlock_irq(&ha->hardware_lock);
 ha->interrupts_on = 1;
}

void
qla82xx_disable_intrs(struct qla_hw_data *ha)
{
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 if (ha->interrupts_on)
  qla82xx_mbx_intr_disable(vha);

 spin_lock_irq(&ha->hardware_lock);
 if (IS_QLA8044(ha))
  qla8044_wr_reg(ha, LEG_INTR_MASK_OFFSET, 1);
 else
  qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400);
 spin_unlock_irq(&ha->hardware_lock);
 ha->interrupts_on = 0;
}

void qla82xx_init_flags(struct qla_hw_data *ha)
{
 struct qla82xx_legacy_intr_set *nx_legacy_intr;

 /* ISP 8021 initializations */
 rwlock_init(&ha->hw_lock);
 ha->qdr_sn_window = -1;
 ha->ddr_mn_window = -1;
 ha->curr_window = 255;
 ha->portnum = PCI_FUNC(ha->pdev->devfn);
 nx_legacy_intr = &legacy_intr[ha->portnum];
 ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit;
 ha->nx_legacy_intr.tgt_status_reg = nx_legacy_intr->tgt_status_reg;
 ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg;
 ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg;
}

static inline void
qla82xx_set_idc_version(scsi_qla_host_t *vha)
{
 int idc_ver;
 uint32_t drv_active;
 struct qla_hw_data *ha = vha->hw;

 drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
 if (drv_active == (QLA82XX_DRV_ACTIVE << (ha->portnum * 4))) {
  qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION,
      QLA82XX_IDC_VERSION);
  ql_log(ql_log_info, vha, 0xb082,
      "IDC version updated to %d\n", QLA82XX_IDC_VERSION);
 } else {
  idc_ver = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_IDC_VERSION);
  if (idc_ver != QLA82XX_IDC_VERSION)
   ql_log(ql_log_info, vha, 0xb083,
       "qla2xxx driver IDC version %d is not compatible "
       "with IDC version %d of the other drivers\n",
       QLA82XX_IDC_VERSION, idc_ver);
 }
}

inline void
qla82xx_set_drv_active(scsi_qla_host_t *vha)
{
 uint32_t drv_active;
 struct qla_hw_data *ha = vha->hw;

 drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);

 /* If reset value is all FF's, initialize DRV_ACTIVE */
 if (drv_active == 0xffffffff) {
  qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE,
   QLA82XX_DRV_NOT_ACTIVE);
  drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
 }
 drv_active |= (QLA82XX_DRV_ACTIVE << (ha->portnum * 4));
 qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active);
}

inline void
qla82xx_clear_drv_active(struct qla_hw_data *ha)
{
 uint32_t drv_active;

 drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
 drv_active &= ~(QLA82XX_DRV_ACTIVE << (ha->portnum * 4));
 qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active);
}

static inline int
qla82xx_need_reset(struct qla_hw_data *ha)
{
 uint32_t drv_state;
 int rval;

 if (ha->flags.nic_core_reset_owner)
  return 1;
 else {
  drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
  rval = drv_state & (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4));
  return rval;
 }
}

static inline void
qla82xx_set_rst_ready(struct qla_hw_data *ha)
{
 uint32_t drv_state;
 scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);

 drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);

 /* If reset value is all FF's, initialize DRV_STATE */
 if (drv_state == 0xffffffff) {
  qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, QLA82XX_DRVST_NOT_RDY);
  drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
 }
 drv_state |= (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4));
 ql_dbg(ql_dbg_init, vha, 0x00bb,
     "drv_state = 0x%08x.\n", drv_state);
 qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state);
}

static inline void
qla82xx_clear_rst_ready(struct qla_hw_data *ha)
{
 uint32_t drv_state;

 drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
 drv_state &= ~(QLA82XX_DRVST_RST_RDY << (ha->portnum * 4));
 qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state);
}

static inline void
qla82xx_set_qsnt_ready(struct qla_hw_data *ha)
{
 uint32_t qsnt_state;

 qsnt_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
 qsnt_state |= (QLA82XX_DRVST_QSNT_RDY << (ha->portnum * 4));
 qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state);
}

void
qla82xx_clear_qsnt_ready(scsi_qla_host_t *vha)
{
 struct qla_hw_data *ha = vha->hw;
 uint32_t qsnt_state;

 qsnt_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
 qsnt_state &= ~(QLA82XX_DRVST_QSNT_RDY << (ha->portnum * 4));
 qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state);
}

static int
qla82xx_load_fw(scsi_qla_host_t *vha)
{
 int rst;
 struct fw_blob *blob;
 struct qla_hw_data *ha = vha->hw;

 if (qla82xx_pinit_from_rom(vha) != QLA_SUCCESS) {
  ql_log(ql_log_fatal, vha, 0x009f,
      "Error during CRB initialization.\n");
  return QLA_FUNCTION_FAILED;
 }
 udelay(500);

 /* Bring QM and CAMRAM out of reset */
 rst = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET);
 rst &= ~((1 << 28) | (1 << 24));
 qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, rst);

 /*
 * FW Load priority:
 * 1) Operational firmware residing in flash.
 * 2) Firmware via request-firmware interface (.bin file).
 */

 if (ql2xfwloadbin == 2)
  goto try_blob_fw;

 ql_log(ql_log_info, vha, 0x00a0,
     "Attempting to load firmware from flash.\n");

 if (qla82xx_fw_load_from_flash(ha) == QLA_SUCCESS) {
  ql_log(ql_log_info, vha, 0x00a1,
      "Firmware loaded successfully from flash.\n");
  return QLA_SUCCESS;
 } else {
  ql_log(ql_log_warn, vha, 0x0108,
      "Firmware load from flash failed.\n");
 }

try_blob_fw:
 ql_log(ql_log_info, vha, 0x00a2,
     "Attempting to load firmware from blob.\n");

 /* Load firmware blob. */
 blob = ha->hablob = qla2x00_request_firmware(vha);
 if (!blob) {
  ql_log(ql_log_fatal, vha, 0x00a3,
      "Firmware image not present.\n");
  goto fw_load_failed;
 }

 /* Validating firmware blob */
 if (qla82xx_validate_firmware_blob(vha,
  QLA82XX_FLASH_ROMIMAGE)) {
  /* Fallback to URI format */
  if (qla82xx_validate_firmware_blob(vha,
   QLA82XX_UNIFIED_ROMIMAGE)) {
   ql_log(ql_log_fatal, vha, 0x00a4,
       "No valid firmware image found.\n");
   return QLA_FUNCTION_FAILED;
  }
 }

 if (qla82xx_fw_load_from_blob(ha) == QLA_SUCCESS) {
  ql_log(ql_log_info, vha, 0x00a5,
      "Firmware loaded successfully from binary blob.\n");
  return QLA_SUCCESS;
 }

 ql_log(ql_log_fatal, vha, 0x00a6,
        "Firmware load failed for binary blob.\n");
 blob->fw = NULL;
 blob = NULL;

fw_load_failed:
 return QLA_FUNCTION_FAILED;
}

int
qla82xx_start_firmware(scsi_qla_host_t *vha)
{
 uint16_t      lnk;
 struct qla_hw_data *ha = vha->hw;

 /* scrub dma mask expansion register */
 qla82xx_wr_32(ha, CRB_DMA_SHIFT, QLA82XX_DMA_SHIFT_VALUE);

 /* Put both the PEG CMD and RCV PEG to default state
 * of 0 before resetting the hardware
 */

 qla82xx_wr_32(ha, CRB_CMDPEG_STATE, 0);
 qla82xx_wr_32(ha, CRB_RCVPEG_STATE, 0);

 /* Overwrite stale initialization register values */
 qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS1, 0);
 qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS2, 0);

 if (qla82xx_load_fw(vha) != QLA_SUCCESS) {
  ql_log(ql_log_fatal, vha, 0x00a7,
      "Error trying to start fw.\n");
  return QLA_FUNCTION_FAILED;
 }

 /* Handshake with the card before we register the devices. */
 if (qla82xx_check_cmdpeg_state(ha) != QLA_SUCCESS) {
  ql_log(ql_log_fatal, vha, 0x00aa,
      "Error during card handshake.\n");
  return QLA_FUNCTION_FAILED;
 }

 /* Negotiated Link width */
 pcie_capability_read_word(ha->pdev, PCI_EXP_LNKSTA, &lnk);
 ha->link_width = (lnk >> 4) & 0x3f;

 /* Synchronize with Receive peg */
 return qla82xx_check_rcvpeg_state(ha);
}

static __le32 *
qla82xx_read_flash_data(scsi_qla_host_t *vha, __le32 *dwptr, uint32_t faddr,
 uint32_t length)
{
 uint32_t i;
 uint32_t val;
 struct qla_hw_data *ha = vha->hw;

 /* Dword reads to flash. */
 for (i = 0; i < length/4; i++, faddr += 4) {
  if (qla82xx_rom_fast_read(ha, faddr, &val)) {
   ql_log(ql_log_warn, vha, 0x0106,
       "Do ROM fast read failed.\n");
   goto done_read;
  }
  dwptr[i] = cpu_to_le32(val);
 }
done_read:
 return dwptr;
}

static int
qla82xx_unprotect_flash(struct qla_hw_data *ha)
{
 int ret;
 uint32_t val;
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=94 H=95 G=94

¤ Dauer der Verarbeitung: 0.23 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.