summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c11
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.c53
2 files changed, 58 insertions, 6 deletions
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index ee2de177d0d0..d21078ca7fb3 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -466,9 +466,12 @@ static int pm8001_ioremap(struct pm8001_hba_info *pm8001_ha)
pm8001_ha->io_mem[logicalBar].memvirtaddr =
ioremap(pm8001_ha->io_mem[logicalBar].membase,
pm8001_ha->io_mem[logicalBar].memsize);
- pm8001_dbg(pm8001_ha, INIT,
- "PCI: bar %d, logicalBar %d\n",
+ if (!pm8001_ha->io_mem[logicalBar].memvirtaddr) {
+ pm8001_dbg(pm8001_ha, INIT,
+ "Failed to ioremap bar %d, logicalBar %d",
bar, logicalBar);
+ return -ENOMEM;
+ }
pm8001_dbg(pm8001_ha, INIT,
"base addr %llx virt_addr=%llx len=%d\n",
(u64)pm8001_ha->io_mem[logicalBar].membase,
@@ -540,9 +543,11 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev,
tasklet_init(&pm8001_ha->tasklet[j], pm8001_tasklet,
(unsigned long)&(pm8001_ha->irq_vector[j]));
#endif
- pm8001_ioremap(pm8001_ha);
+ if (pm8001_ioremap(pm8001_ha))
+ goto failed_pci_alloc;
if (!pm8001_alloc(pm8001_ha, ent))
return pm8001_ha;
+failed_pci_alloc:
pm8001_free(pm8001_ha);
return NULL;
}
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index 86a3d483749c..7d0eada11d3c 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -1115,7 +1115,7 @@ static int check_fw_ready(struct pm8001_hba_info *pm8001_ha)
return ret;
}
-static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
+static int init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
{
void __iomem *base_addr;
u32 value;
@@ -1124,15 +1124,48 @@ static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
u32 pcilogic;
value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0);
+
+ /**
+ * lower 26 bits of SCRATCHPAD0 register describes offset within the
+ * PCIe BAR where the MPI configuration table is present
+ */
offset = value & 0x03FFFFFF; /* scratch pad 0 TBL address */
pm8001_dbg(pm8001_ha, DEV, "Scratchpad 0 Offset: 0x%x value 0x%x\n",
offset, value);
+ /**
+ * Upper 6 bits describe the offset within PCI config space where BAR
+ * is located.
+ */
pcilogic = (value & 0xFC000000) >> 26;
pcibar = get_pci_bar_index(pcilogic);
pm8001_dbg(pm8001_ha, INIT, "Scratchpad 0 PCI BAR: %d\n", pcibar);
+
+ /**
+ * Make sure the offset falls inside the ioremapped PCI BAR
+ */
+ if (offset > pm8001_ha->io_mem[pcibar].memsize) {
+ pm8001_dbg(pm8001_ha, FAIL,
+ "Main cfg tbl offset outside %u > %u\n",
+ offset, pm8001_ha->io_mem[pcibar].memsize);
+ return -EBUSY;
+ }
pm8001_ha->main_cfg_tbl_addr = base_addr =
pm8001_ha->io_mem[pcibar].memvirtaddr + offset;
+
+ /**
+ * Validate main configuration table address: first DWord should read
+ * "PMCS"
+ */
+ value = pm8001_mr32(pm8001_ha->main_cfg_tbl_addr, 0);
+ if (memcmp(&value, "PMCS", 4) != 0) {
+ pm8001_dbg(pm8001_ha, FAIL,
+ "BAD main config signature 0x%x\n",
+ value);
+ return -EBUSY;
+ }
+ pm8001_dbg(pm8001_ha, INIT,
+ "VALID main config signature 0x%x\n", value);
pm8001_ha->general_stat_tbl_addr =
base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x18) &
0xFFFFFF);
@@ -1171,6 +1204,7 @@ static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
pm8001_dbg(pm8001_ha, INIT, "addr - pspa %p ivt %p\n",
pm8001_ha->pspa_q_tbl_addr,
pm8001_ha->ivt_tbl_addr);
+ return 0;
}
/**
@@ -1438,7 +1472,12 @@ static int pm80xx_chip_init(struct pm8001_hba_info *pm8001_ha)
pm8001_ha->controller_fatal_error = false;
/* Initialize pci space address eg: mpi offset */
- init_pci_device_addresses(pm8001_ha);
+ ret = init_pci_device_addresses(pm8001_ha);
+ if (ret) {
+ pm8001_dbg(pm8001_ha, FAIL,
+ "Failed to init pci addresses");
+ return ret;
+ }
init_default_table_values(pm8001_ha);
read_main_config_table(pm8001_ha);
read_general_status_table(pm8001_ha);
@@ -1482,7 +1521,15 @@ static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha)
u32 max_wait_count;
u32 value;
u32 gst_len_mpistate;
- init_pci_device_addresses(pm8001_ha);
+ int ret;
+
+ ret = init_pci_device_addresses(pm8001_ha);
+ if (ret) {
+ pm8001_dbg(pm8001_ha, FAIL,
+ "Failed to init pci addresses");
+ return ret;
+ }
+
/* Write bit1=1 to Inbound DoorBell Register to tell the SPC FW the
table is stop */
pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPCv_MSGU_CFG_TABLE_RESET);