|
@@ -1430,6 +1430,98 @@ mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
|
|
|
sprintf(prod_name, "%s", product_str);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * mpt_mapresources - map in memory mapped io
|
|
|
+ * @ioc: Pointer to pointer to IOC adapter
|
|
|
+ *
|
|
|
+ **/
|
|
|
+static int
|
|
|
+mpt_mapresources(MPT_ADAPTER *ioc)
|
|
|
+{
|
|
|
+ u8 __iomem *mem;
|
|
|
+ int ii;
|
|
|
+ unsigned long mem_phys;
|
|
|
+ unsigned long port;
|
|
|
+ u32 msize;
|
|
|
+ u32 psize;
|
|
|
+ u8 revision;
|
|
|
+ int r = -ENODEV;
|
|
|
+ struct pci_dev *pdev;
|
|
|
+
|
|
|
+ pdev = ioc->pcidev;
|
|
|
+ ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
|
|
|
+ if (pci_enable_device_mem(pdev)) {
|
|
|
+ printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
|
|
|
+ "failed\n", ioc->name);
|
|
|
+ return r;
|
|
|
+ }
|
|
|
+ if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
|
|
|
+ printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
|
|
|
+ "MEM failed\n", ioc->name);
|
|
|
+ return r;
|
|
|
+ }
|
|
|
+
|
|
|
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
|
|
|
+
|
|
|
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)
|
|
|
+ && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
|
|
|
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
|
|
|
+ ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
|
|
|
+ ioc->name));
|
|
|
+ } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)
|
|
|
+ && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
|
|
|
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
|
|
|
+ ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
|
|
|
+ ioc->name));
|
|
|
+ } else {
|
|
|
+ printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
|
|
|
+ ioc->name, pci_name(pdev));
|
|
|
+ pci_release_selected_regions(pdev, ioc->bars);
|
|
|
+ return r;
|
|
|
+ }
|
|
|
+
|
|
|
+ mem_phys = msize = 0;
|
|
|
+ port = psize = 0;
|
|
|
+ for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
|
|
|
+ if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
|
|
|
+ if (psize)
|
|
|
+ continue;
|
|
|
+ /* Get I/O space! */
|
|
|
+ port = pci_resource_start(pdev, ii);
|
|
|
+ psize = pci_resource_len(pdev, ii);
|
|
|
+ } else {
|
|
|
+ if (msize)
|
|
|
+ continue;
|
|
|
+ /* Get memmap */
|
|
|
+ mem_phys = pci_resource_start(pdev, ii);
|
|
|
+ msize = pci_resource_len(pdev, ii);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ioc->mem_size = msize;
|
|
|
+
|
|
|
+ mem = NULL;
|
|
|
+ /* Get logical ptr for PciMem0 space */
|
|
|
+ /*mem = ioremap(mem_phys, msize);*/
|
|
|
+ mem = ioremap(mem_phys, msize);
|
|
|
+ if (mem == NULL) {
|
|
|
+ printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
|
|
|
+ " memory!\n", ioc->name);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ ioc->memmap = mem;
|
|
|
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
|
|
|
+ ioc->name, mem, mem_phys));
|
|
|
+
|
|
|
+ ioc->mem_phys = mem_phys;
|
|
|
+ ioc->chip = (SYSIF_REGS __iomem *)mem;
|
|
|
+
|
|
|
+ /* Save Port IO values in case we need to do downloadboot */
|
|
|
+ ioc->pio_mem_phys = port;
|
|
|
+ ioc->pio_chip = (SYSIF_REGS __iomem *)port;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
/**
|
|
|
* mpt_attach - Install a PCI intelligent MPT adapter.
|
|
@@ -1452,13 +1544,6 @@ int
|
|
|
mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
|
{
|
|
|
MPT_ADAPTER *ioc;
|
|
|
- u8 __iomem *mem;
|
|
|
- u8 __iomem *pmem;
|
|
|
- unsigned long mem_phys;
|
|
|
- unsigned long port;
|
|
|
- u32 msize;
|
|
|
- u32 psize;
|
|
|
- int ii;
|
|
|
u8 cb_idx;
|
|
|
int r = -ENODEV;
|
|
|
u8 revision;
|
|
@@ -1468,52 +1553,32 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
|
struct proc_dir_entry *dent, *ent;
|
|
|
#endif
|
|
|
|
|
|
- if (mpt_debug_level)
|
|
|
- printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
|
|
|
-
|
|
|
ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
|
|
|
if (ioc == NULL) {
|
|
|
printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
- ioc->debug_level = mpt_debug_level;
|
|
|
+
|
|
|
ioc->id = mpt_ids++;
|
|
|
sprintf(ioc->name, "ioc%d", ioc->id);
|
|
|
|
|
|
- ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
|
|
|
- if (pci_enable_device_mem(pdev)) {
|
|
|
- printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
|
|
|
- "failed\n", ioc->name);
|
|
|
- kfree(ioc);
|
|
|
- return r;
|
|
|
- }
|
|
|
- if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
|
|
|
- printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
|
|
|
- "MEM failed\n", ioc->name);
|
|
|
- kfree(ioc);
|
|
|
- return r;
|
|
|
- }
|
|
|
+ /*
|
|
|
+ * set initial debug level
|
|
|
+ * (refer to mptdebug.h)
|
|
|
+ *
|
|
|
+ */
|
|
|
+ ioc->debug_level = mpt_debug_level;
|
|
|
+ if (mpt_debug_level)
|
|
|
+ printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
|
|
|
|
|
|
dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
|
|
|
|
|
|
- if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
|
|
|
- dprintk(ioc, printk(MYIOC_s_INFO_FMT
|
|
|
- ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", ioc->name));
|
|
|
- } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
|
|
|
- printk(MYIOC_s_WARN_FMT ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n",
|
|
|
- ioc->name);
|
|
|
+ ioc->pcidev = pdev;
|
|
|
+ if (mpt_mapresources(ioc)) {
|
|
|
kfree(ioc);
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
- if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
|
|
|
- dprintk(ioc, printk(MYIOC_s_INFO_FMT
|
|
|
- ": Using 64 bit consistent mask\n", ioc->name));
|
|
|
- } else {
|
|
|
- dprintk(ioc, printk(MYIOC_s_INFO_FMT
|
|
|
- ": Not using 64 bit consistent mask\n", ioc->name));
|
|
|
- }
|
|
|
-
|
|
|
ioc->alloc_total = sizeof(MPT_ADAPTER);
|
|
|
ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
|
|
|
ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
|
|
@@ -1551,48 +1616,9 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
|
/* Find lookup slot. */
|
|
|
INIT_LIST_HEAD(&ioc->list);
|
|
|
|
|
|
- mem_phys = msize = 0;
|
|
|
- port = psize = 0;
|
|
|
- for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
|
|
|
- if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
|
|
|
- if (psize)
|
|
|
- continue;
|
|
|
- /* Get I/O space! */
|
|
|
- port = pci_resource_start(pdev, ii);
|
|
|
- psize = pci_resource_len(pdev,ii);
|
|
|
- } else {
|
|
|
- if (msize)
|
|
|
- continue;
|
|
|
- /* Get memmap */
|
|
|
- mem_phys = pci_resource_start(pdev, ii);
|
|
|
- msize = pci_resource_len(pdev,ii);
|
|
|
- }
|
|
|
- }
|
|
|
- ioc->mem_size = msize;
|
|
|
-
|
|
|
- mem = NULL;
|
|
|
- /* Get logical ptr for PciMem0 space */
|
|
|
- /*mem = ioremap(mem_phys, msize);*/
|
|
|
- mem = ioremap(mem_phys, msize);
|
|
|
- if (mem == NULL) {
|
|
|
- printk(MYIOC_s_ERR_FMT "Unable to map adapter memory!\n", ioc->name);
|
|
|
- kfree(ioc);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- ioc->memmap = mem;
|
|
|
- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", ioc->name, mem, mem_phys));
|
|
|
-
|
|
|
dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
|
|
|
ioc->name, &ioc->facts, &ioc->pfacts[0]));
|
|
|
|
|
|
- ioc->mem_phys = mem_phys;
|
|
|
- ioc->chip = (SYSIF_REGS __iomem *)mem;
|
|
|
-
|
|
|
- /* Save Port IO values in case we need to do downloadboot */
|
|
|
- ioc->pio_mem_phys = port;
|
|
|
- pmem = (u8 __iomem *)port;
|
|
|
- ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
|
|
|
-
|
|
|
pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
|
|
|
mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
|
|
|
|
|
@@ -1688,7 +1714,9 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
|
list_del(&ioc->list);
|
|
|
if (ioc->alt_ioc)
|
|
|
ioc->alt_ioc->alt_ioc = NULL;
|
|
|
- iounmap(mem);
|
|
|
+ iounmap(ioc->memmap);
|
|
|
+ if (r != -5)
|
|
|
+ pci_release_selected_regions(pdev, ioc->bars);
|
|
|
kfree(ioc);
|
|
|
pci_set_drvdata(pdev, NULL);
|
|
|
return r;
|
|
@@ -1784,13 +1812,10 @@ mpt_suspend(struct pci_dev *pdev, pm_message_t state)
|
|
|
u32 device_state;
|
|
|
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
|
|
|
|
|
|
- device_state=pci_choose_state(pdev, state);
|
|
|
-
|
|
|
- printk(MYIOC_s_INFO_FMT
|
|
|
- "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
|
|
|
- ioc->name, pdev, pci_name(pdev), device_state);
|
|
|
-
|
|
|
- pci_save_state(pdev);
|
|
|
+ device_state = pci_choose_state(pdev, state);
|
|
|
+ printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
|
|
|
+ "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
|
|
|
+ device_state);
|
|
|
|
|
|
/* put ioc into READY_STATE */
|
|
|
if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
|
|
@@ -1805,10 +1830,14 @@ mpt_suspend(struct pci_dev *pdev, pm_message_t state)
|
|
|
/* Clear any lingering interrupt */
|
|
|
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
|
|
|
|
|
|
+ free_irq(ioc->pci_irq, ioc);
|
|
|
+ if (mpt_msi_enable)
|
|
|
+ pci_disable_msi(ioc->pcidev);
|
|
|
+ ioc->pci_irq = -1;
|
|
|
+ pci_save_state(pdev);
|
|
|
pci_disable_device(pdev);
|
|
|
pci_release_selected_regions(pdev, ioc->bars);
|
|
|
pci_set_power_state(pdev, device_state);
|
|
|
-
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1823,48 +1852,54 @@ mpt_resume(struct pci_dev *pdev)
|
|
|
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
|
|
|
u32 device_state = pdev->current_state;
|
|
|
int recovery_state;
|
|
|
+ int err;
|
|
|
|
|
|
- printk(MYIOC_s_INFO_FMT
|
|
|
- "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
|
|
|
- ioc->name, pdev, pci_name(pdev), device_state);
|
|
|
+ printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
|
|
|
+ "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
|
|
|
+ device_state);
|
|
|
|
|
|
- pci_set_power_state(pdev, 0);
|
|
|
+ pci_set_power_state(pdev, PCI_D0);
|
|
|
+ pci_enable_wake(pdev, PCI_D0, 0);
|
|
|
pci_restore_state(pdev);
|
|
|
- if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
|
|
|
- ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
|
|
|
- IORESOURCE_IO);
|
|
|
- if (pci_enable_device(pdev))
|
|
|
- return 0;
|
|
|
- } else {
|
|
|
- ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
|
|
|
- if (pci_enable_device_mem(pdev))
|
|
|
- return 0;
|
|
|
- }
|
|
|
- if (pci_request_selected_regions(pdev, ioc->bars, "mpt"))
|
|
|
- return 0;
|
|
|
+ ioc->pcidev = pdev;
|
|
|
+ err = mpt_mapresources(ioc);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
|
|
|
- /* enable interrupts */
|
|
|
- CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
|
|
|
- ioc->active = 1;
|
|
|
+ printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
|
|
|
+ ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
|
|
|
+ CHIPREG_READ32(&ioc->chip->Doorbell));
|
|
|
|
|
|
- printk(MYIOC_s_INFO_FMT
|
|
|
- "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
|
|
|
- ioc->name,
|
|
|
- (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
|
|
|
- CHIPREG_READ32(&ioc->chip->Doorbell));
|
|
|
+ /*
|
|
|
+ * Errata workaround for SAS pci express:
|
|
|
+ * Upon returning to the D0 state, the contents of the doorbell will be
|
|
|
+ * stale data, and this will incorrectly signal to the host driver that
|
|
|
+ * the firmware is ready to process mpt commands. The workaround is
|
|
|
+ * to issue a diagnostic reset.
|
|
|
+ */
|
|
|
+ if (ioc->bus_type == SAS && (pdev->device ==
|
|
|
+ MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
|
|
|
+ MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
|
|
|
+ if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
|
|
|
+ printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
|
|
|
+ ioc->name);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/* bring ioc to operational state */
|
|
|
- if ((recovery_state = mpt_do_ioc_recovery(ioc,
|
|
|
- MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
|
|
|
- printk(MYIOC_s_INFO_FMT
|
|
|
- "pci-resume: Cannot recover, error:[%x]\n",
|
|
|
- ioc->name, recovery_state);
|
|
|
- } else {
|
|
|
+ printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
|
|
|
+ recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
|
|
|
+ CAN_SLEEP);
|
|
|
+ if (recovery_state != 0)
|
|
|
+ printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
|
|
|
+ "error:[%x]\n", ioc->name, recovery_state);
|
|
|
+ else
|
|
|
printk(MYIOC_s_INFO_FMT
|
|
|
- "pci-resume: success\n", ioc->name);
|
|
|
- }
|
|
|
-
|
|
|
+ "pci-resume: success\n", ioc->name);
|
|
|
+ out:
|
|
|
return 0;
|
|
|
+
|
|
|
}
|
|
|
#endif
|
|
|
|
|
@@ -1903,6 +1938,7 @@ mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
|
|
|
* -3 if READY but PrimeIOCFifos Failed
|
|
|
* -4 if READY but IOCInit Failed
|
|
|
* -5 if failed to enable_device and/or request_selected_regions
|
|
|
+ * -6 if failed to upload firmware
|
|
|
*/
|
|
|
static int
|
|
|
mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
|
|
@@ -2097,7 +2133,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
|
|
|
} else {
|
|
|
printk(MYIOC_s_WARN_FMT
|
|
|
"firmware upload failure!\n", ioc->name);
|
|
|
- ret = -5;
|
|
|
+ ret = -6;
|
|
|
}
|
|
|
}
|
|
|
}
|