summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2009-10-02 12:45:59 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2009-10-02 12:45:59 +1000
commit862e23f59a1838846f3254cd25f26868812db9d9 (patch)
treeecf7b3073d02e199dad8996a5953fc0fe4f2b732
parent295cf4ace24c534d653d478335a4d0c4d8140650 (diff)
parent15addcb9e65e9b7a9df5978ee7f105ce2afee257 (diff)
Merge remote branch 'scsi-post-merge/master'
Conflicts: MAINTAINERS drivers/scsi/fcoe/fcoe.c drivers/scsi/fcoe/fcoe.h drivers/scsi/libfc/fc_elsct.c drivers/scsi/libfc/fc_lport.c drivers/scsi/pmcraid.c drivers/scsi/pmcraid.h include/scsi/fc_encode.h include/scsi/libfc.h kernel/sysctl.c
-rw-r--r--drivers/ata/ahci.c54
-rw-r--r--drivers/message/fusion/mptbase.c99
-rw-r--r--drivers/message/fusion/mptbase.h3
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c78
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h5
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h1
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c36
-rw-r--r--include/linux/libata.h2
8 files changed, 206 insertions, 72 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index acd1162712b1..a8f830f0cef3 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -45,6 +45,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
+#include <linux/blk-iopoll.h>
#define DRV_NAME "ahci"
#define DRV_VERSION "3.0"
@@ -2114,7 +2115,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
ata_port_abort(ap);
}
-static void ahci_port_intr(struct ata_port *ap)
+static int ahci_port_intr(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
struct ata_eh_info *ehi = &ap->link.eh_info;
@@ -2144,7 +2145,7 @@ static void ahci_port_intr(struct ata_port *ap)
if (unlikely(status & PORT_IRQ_ERROR)) {
ahci_error_intr(ap, status);
- return;
+ return 0;
}
if (status & PORT_IRQ_SDB_FIS) {
@@ -2185,7 +2186,43 @@ static void ahci_port_intr(struct ata_port *ap)
ehi->err_mask |= AC_ERR_HSM;
ehi->action |= ATA_EH_RESET;
ata_port_freeze(ap);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+static void ap_irq_disable(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+
+ writel(0, port_mmio + PORT_IRQ_MASK);
+}
+
+static void ap_irq_enable(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
+
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+}
+
+static int ahci_iopoll(struct blk_iopoll *iop, int budget)
+{
+ struct ata_port *ap = container_of(iop, struct ata_port, iopoll);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&ap->host->lock, flags);
+ ret = ahci_port_intr(ap);
+ spin_unlock_irqrestore(&ap->host->lock, flags);
+
+ if (ret < budget) {
+ blk_iopoll_complete(iop);
+ ap_irq_enable(ap);
}
+
+ return ret;
}
static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
@@ -2218,7 +2255,12 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
ap = host->ports[i];
if (ap) {
- ahci_port_intr(ap);
+ if (!blk_iopoll_enabled)
+ ahci_port_intr(ap);
+ else if (!blk_iopoll_sched_prep(&ap->iopoll)) {
+ ap_irq_disable(ap);
+ blk_iopoll_sched(&ap->iopoll);
+ }
VPRINTK("port %u\n", i);
} else {
VPRINTK("port %u (no irq)\n", i);
@@ -2352,6 +2394,8 @@ static void ahci_pmp_detach(struct ata_port *ap)
static int ahci_port_resume(struct ata_port *ap)
{
+ blk_iopoll_enable(&ap->iopoll);
+
ahci_power_up(ap);
ahci_start_port(ap);
@@ -2482,6 +2526,8 @@ static int ahci_port_start(struct ata_port *ap)
ap->private_data = pp;
+ blk_iopoll_init(&ap->iopoll, 32, ahci_iopoll);
+
/* engage engines, captain */
return ahci_port_resume(ap);
}
@@ -2495,6 +2541,8 @@ static void ahci_port_stop(struct ata_port *ap)
rc = ahci_deinit_port(ap, &emsg);
if (rc)
ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
+
+ blk_iopoll_disable(&ap->iopoll);
}
static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 610e914abe6c..33d8bac31847 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -114,6 +114,9 @@ module_param_call(mpt_fwfault_debug, param_set_int, param_get_int,
MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
" and halt Firmware on fault - (default=0)");
+static int mpt_iopoll_w = 32;
+module_param(mpt_iopoll_w, int, 0);
+MODULE_PARM_DESC(mpt_iopoll_w, " blk iopoll budget (default=32");
#ifdef MFCNT
@@ -515,6 +518,44 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
mb();
}
+static void mpt_irq_disable(MPT_ADAPTER *ioc)
+{
+ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
+ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+ CHIPREG_READ32(&ioc->chip->IntStatus);
+}
+
+static void mpt_irq_enable(MPT_ADAPTER *ioc)
+{
+ CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
+}
+
+static inline void __mpt_handle_irq(MPT_ADAPTER *ioc, u32 pa)
+{
+ if (pa & MPI_ADDRESS_REPLY_A_BIT)
+ mpt_reply(ioc, pa);
+ else
+ mpt_turbo_reply(ioc, pa);
+}
+
+static int mpt_handle_irq(MPT_ADAPTER *ioc, unsigned int budget)
+{
+ int nr = 0;
+ u32 pa;
+
+ /*
+ * Drain the reply FIFO!
+ */
+ while ((pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo)) != 0xffffffff) {
+ nr++;
+ __mpt_handle_irq(ioc, pa);
+ if (nr == budget)
+ break;
+ }
+
+ return nr;
+}
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
@@ -536,23 +577,48 @@ static irqreturn_t
mpt_interrupt(int irq, void *bus_id)
{
MPT_ADAPTER *ioc = bus_id;
- u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
+ int nr = 0;
+
+ if (!blk_iopoll_enabled)
+ nr = mpt_handle_irq(ioc, -1U);
+ else if (!blk_iopoll_sched_prep(&ioc->iopoll)) {
+ mpt_irq_disable(ioc);
+ ioc->iopoll.data =CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
+ blk_iopoll_sched(&ioc->iopoll);
+ nr = 1;
+ } else {
+ /*
+ * Not really handled, but it will be by iopoll.
+ */
+ nr = 1;
+ }
- if (pa == 0xFFFFFFFF)
- return IRQ_NONE;
+ if (nr)
+ return IRQ_HANDLED;
- /*
- * Drain the reply FIFO!
- */
- do {
- if (pa & MPI_ADDRESS_REPLY_A_BIT)
- mpt_reply(ioc, pa);
- else
- mpt_turbo_reply(ioc, pa);
- pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
- } while (pa != 0xFFFFFFFF);
+ return IRQ_NONE;
+}
- return IRQ_HANDLED;
+static int mpt_iopoll(struct blk_iopoll *iop, int budget)
+{
+ MPT_ADAPTER *ioc = container_of(iop, MPT_ADAPTER, iopoll);
+ int ret = 0;
+ u32 pa;
+
+ pa = iop->data;
+ iop->data = 0xffffffff;
+ if (pa != 0xffffffff) {
+ __mpt_handle_irq(ioc, pa);
+ ret = 1;
+ }
+
+ ret += mpt_handle_irq(ioc, budget - ret);
+ if (ret < budget) {
+ blk_iopoll_complete(iop);
+ mpt_irq_enable(ioc);
+ }
+
+ return ret;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2087,6 +2153,7 @@ mpt_suspend(struct pci_dev *pdev, pm_message_t state)
/* Clear any lingering interrupt */
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+ blk_iopoll_disable(&ioc->iopoll);
free_irq(ioc->pci_irq, ioc);
if (ioc->msi_enable)
pci_disable_msi(ioc->pcidev);
@@ -2352,6 +2419,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
ret = -EBUSY;
goto out;
}
+ blk_iopoll_init(&ioc->iopoll, mpt_iopoll_w, mpt_iopoll);
+ blk_iopoll_enable(&ioc->iopoll);
irq_allocated = 1;
ioc->pci_irq = ioc->pcidev->irq;
pci_set_master(ioc->pcidev); /* ?? */
@@ -2544,6 +2613,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
out:
if ((ret != 0) && irq_allocated) {
+ blk_iopoll_disable(&ioc->iopoll);
free_irq(ioc->pci_irq, ioc);
if (ioc->msi_enable)
pci_disable_msi(ioc->pcidev);
@@ -2752,6 +2822,7 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
mpt_adapter_disable(ioc);
if (ioc->pci_irq != -1) {
+ blk_iopoll_disable(&ioc->iopoll);
free_irq(ioc->pci_irq, ioc);
if (ioc->msi_enable)
pci_disable_msi(ioc->pcidev);
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index 8dd4d219e433..eb000e07e03e 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -52,6 +52,7 @@
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/mutex.h>
+#include <linux/blk-iopoll.h>
#include "lsi/mpi_type.h"
#include "lsi/mpi.h" /* Fusion MPI(nterface) basic defs */
@@ -764,6 +765,8 @@ typedef struct _MPT_ADAPTER
struct workqueue_struct *reset_work_q;
struct delayed_work fault_reset_work;
+ struct blk_iopoll iopoll;
+
u8 sg_addr_size;
u8 in_rescan;
u8 SGE_size;
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index cca8e4ab0372..cb2eca4c26d8 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -377,6 +377,24 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
return ptr + sizeof(struct qla2xxx_mq_chain);
}
+static void
+qla2xxx_dump_post_process(scsi_qla_host_t *vha, int rval)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (rval != QLA_SUCCESS) {
+ qla_printk(KERN_WARNING, ha,
+ "Failed to dump firmware (%x)!!!\n", rval);
+ ha->fw_dumped = 0;
+ } else {
+ qla_printk(KERN_INFO, ha,
+ "Firmware dump saved to temp buffer (%ld/%p).\n",
+ vha->host_no, ha->fw_dump);
+ ha->fw_dumped = 1;
+ qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP);
+ }
+}
+
/**
* qla2300_fw_dump() - Dumps binary data from the 2300 firmware.
* @ha: HA context
@@ -530,17 +548,7 @@ qla2300_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
if (rval == QLA_SUCCESS)
qla2xxx_copy_queues(ha, nxt);
- if (rval != QLA_SUCCESS) {
- qla_printk(KERN_WARNING, ha,
- "Failed to dump firmware (%x)!!!\n", rval);
- ha->fw_dumped = 0;
-
- } else {
- qla_printk(KERN_INFO, ha,
- "Firmware dump saved to temp buffer (%ld/%p).\n",
- base_vha->host_no, ha->fw_dump);
- ha->fw_dumped = 1;
- }
+ qla2xxx_dump_post_process(base_vha, rval);
qla2300_fw_dump_failed:
if (!hardware_locked)
@@ -737,17 +745,7 @@ qla2100_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
if (rval == QLA_SUCCESS)
qla2xxx_copy_queues(ha, &fw->risc_ram[cnt]);
- if (rval != QLA_SUCCESS) {
- qla_printk(KERN_WARNING, ha,
- "Failed to dump firmware (%x)!!!\n", rval);
- ha->fw_dumped = 0;
-
- } else {
- qla_printk(KERN_INFO, ha,
- "Firmware dump saved to temp buffer (%ld/%p).\n",
- base_vha->host_no, ha->fw_dump);
- ha->fw_dumped = 1;
- }
+ qla2xxx_dump_post_process(base_vha, rval);
qla2100_fw_dump_failed:
if (!hardware_locked)
@@ -984,17 +982,7 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
qla24xx_copy_eft(ha, nxt);
qla24xx_fw_dump_failed_0:
- if (rval != QLA_SUCCESS) {
- qla_printk(KERN_WARNING, ha,
- "Failed to dump firmware (%x)!!!\n", rval);
- ha->fw_dumped = 0;
-
- } else {
- qla_printk(KERN_INFO, ha,
- "Firmware dump saved to temp buffer (%ld/%p).\n",
- base_vha->host_no, ha->fw_dump);
- ha->fw_dumped = 1;
- }
+ qla2xxx_dump_post_process(base_vha, rval);
qla24xx_fw_dump_failed:
if (!hardware_locked)
@@ -1305,17 +1293,7 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
}
qla25xx_fw_dump_failed_0:
- if (rval != QLA_SUCCESS) {
- qla_printk(KERN_WARNING, ha,
- "Failed to dump firmware (%x)!!!\n", rval);
- ha->fw_dumped = 0;
-
- } else {
- qla_printk(KERN_INFO, ha,
- "Firmware dump saved to temp buffer (%ld/%p).\n",
- base_vha->host_no, ha->fw_dump);
- ha->fw_dumped = 1;
- }
+ qla2xxx_dump_post_process(base_vha, rval);
qla25xx_fw_dump_failed:
if (!hardware_locked)
@@ -1628,17 +1606,7 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
}
qla81xx_fw_dump_failed_0:
- if (rval != QLA_SUCCESS) {
- qla_printk(KERN_WARNING, ha,
- "Failed to dump firmware (%x)!!!\n", rval);
- ha->fw_dumped = 0;
-
- } else {
- qla_printk(KERN_INFO, ha,
- "Firmware dump saved to temp buffer (%ld/%p).\n",
- base_vha->host_no, ha->fw_dump);
- ha->fw_dumped = 1;
- }
+ qla2xxx_dump_post_process(base_vha, rval);
qla81xx_fw_dump_failed:
if (!hardware_locked)
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 215061861794..d8ce31040b51 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2123,6 +2123,7 @@ enum qla_work_type {
QLA_EVT_ASYNC_LOGIN_DONE,
QLA_EVT_ASYNC_LOGOUT,
QLA_EVT_ASYNC_LOGOUT_DONE,
+ QLA_EVT_UEVENT,
};
@@ -2146,6 +2147,10 @@ struct qla_work_evt {
#define QLA_LOGIO_LOGIN_RETRIED BIT_0
u16 data[2];
} logio;
+ struct {
+ u32 code;
+#define QLA_UEVENT_CODE_FW_DUMP 0
+ } uevent;
} u;
};
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index f3d1d1afa95b..14e0562851cb 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -92,6 +92,7 @@ extern int qla2x00_post_async_logout_work(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_post_async_logout_done_work(struct scsi_qla_host *,
fc_port_t *, uint16_t *);
+extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index b79fca7d461b..64ff1470e184 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -11,6 +11,7 @@
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
+#include <linux/kobject.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsicam.h>
@@ -2653,6 +2654,38 @@ qla2x00_post_async_work(login_done, QLA_EVT_ASYNC_LOGIN_DONE);
qla2x00_post_async_work(logout, QLA_EVT_ASYNC_LOGOUT);
qla2x00_post_async_work(logout_done, QLA_EVT_ASYNC_LOGOUT_DONE);
+int
+qla2x00_post_uevent_work(struct scsi_qla_host *vha, u32 code)
+{
+ struct qla_work_evt *e;
+
+ e = qla2x00_alloc_work(vha, QLA_EVT_UEVENT);
+ if (!e)
+ return QLA_FUNCTION_FAILED;
+
+ e->u.uevent.code = code;
+ return qla2x00_post_work(vha, e);
+}
+
+static void
+qla2x00_uevent_emit(struct scsi_qla_host *vha, u32 code)
+{
+ char event_string[40];
+ char *envp[] = { event_string, NULL };
+
+ switch (code) {
+ case QLA_UEVENT_CODE_FW_DUMP:
+ snprintf(event_string, sizeof(event_string), "FW_DUMP=%ld",
+ vha->host_no);
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+ kobject_uevent_env(&(&vha->hw->pdev->driver->driver)->owner->mkobj.kobj,
+ KOBJ_CHANGE, envp);
+}
+
void
qla2x00_do_work(struct scsi_qla_host *vha)
{
@@ -2690,6 +2723,9 @@ qla2x00_do_work(struct scsi_qla_host *vha)
qla2x00_async_logout_done(vha, e->u.logio.fcport,
e->u.logio.data);
break;
+ case QLA_EVT_UEVENT:
+ qla2x00_uevent_emit(vha, e->u.uevent.code);
+ break;
}
if (e->flags & QLA_EVT_FLAG_FREE)
kfree(e);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 76319bf03e37..5bdd34433d8e 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -37,6 +37,7 @@
#include <scsi/scsi_host.h>
#include <linux/acpi.h>
#include <linux/cdrom.h>
+#include <linux/blk-iopoll.h>
/*
* Define if arch has non-standard setup. This is a _PCI_ standard
@@ -763,6 +764,7 @@ struct ata_port {
#endif
/* owned by EH */
u8 sector_buf[ATA_SECT_SIZE] ____cacheline_aligned;
+ struct blk_iopoll iopoll;
};
/* The following initializer overrides a method to NULL whether one of