The only generic interface to execute asynchronously in the BH context is
tasklet; however, it's marked deprecated and has some design flaws. To
replace tasklets, BH workqueue support was recently added. A BH workqueue
behaves similarly to regular workqueues except that the queued work items
are executed in the BH context.

This patch converts drivers/scsi/* from tasklet to BH workqueue.

Based on the work done by Tejun Heo <t...@kernel.org>
Branch: https://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git for-6.10

Signed-off-by: Allen Pais <allen.l...@gmail.com>
---
 drivers/scsi/aic7xxx/aic7xxx_osm.c          |  2 +-
 drivers/scsi/aic94xx/aic94xx_hwi.c          | 14 ++--
 drivers/scsi/aic94xx/aic94xx_hwi.h          |  5 +-
 drivers/scsi/aic94xx/aic94xx_scb.c          | 36 +++++-----
 drivers/scsi/aic94xx/aic94xx_task.c         | 14 ++--
 drivers/scsi/aic94xx/aic94xx_tmf.c          | 34 ++++-----
 drivers/scsi/esas2r/esas2r.h                | 12 ++--
 drivers/scsi/esas2r/esas2r_init.c           | 14 ++--
 drivers/scsi/esas2r/esas2r_int.c            | 18 ++---
 drivers/scsi/esas2r/esas2r_io.c             |  2 +-
 drivers/scsi/esas2r/esas2r_main.c           | 16 ++---
 drivers/scsi/ibmvscsi/ibmvfc.c              | 16 ++---
 drivers/scsi/ibmvscsi/ibmvfc.h              |  3 +-
 drivers/scsi/ibmvscsi/ibmvscsi.c            | 16 ++---
 drivers/scsi/ibmvscsi/ibmvscsi.h            |  3 +-
 drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c    | 15 ++--
 drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h    |  3 +-
 drivers/scsi/isci/host.c                    | 12 ++--
 drivers/scsi/isci/host.h                    |  8 +--
 drivers/scsi/isci/init.c                    |  4 +-
 drivers/scsi/megaraid/mega_common.h         |  5 +-
 drivers/scsi/megaraid/megaraid_mbox.c       | 21 +++---
 drivers/scsi/megaraid/megaraid_sas.h        |  4 +-
 drivers/scsi/megaraid/megaraid_sas_base.c   | 32 ++++-----
 drivers/scsi/megaraid/megaraid_sas_fusion.c | 16 ++---
 drivers/scsi/mvsas/mv_init.c                | 27 ++++---
 drivers/scsi/mvsas/mv_sas.h                 |  9 +--
 drivers/scsi/pm8001/pm8001_init.c           | 55 ++++++++-------
 drivers/scsi/pm8001/pm8001_sas.h            |  2 +-
 drivers/scsi/pmcraid.c                      | 78 +++++++++++----------
 drivers/scsi/pmcraid.h                      |  5 +-
 31 files changed, 251 insertions(+), 250 deletions(-)

diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c 
b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index b0c4f2345321..42f76391f589 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -797,7 +797,7 @@ struct scsi_host_template aic7xxx_driver_template = {
        .target_destroy         = ahc_linux_target_destroy,
 };
 
-/**************************** Tasklet Handler 
*********************************/
+/**************************** Work Handler *********************************/
 
 
 static inline unsigned int ahc_build_scsiid(struct ahc_softc *ahc,
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c 
b/drivers/scsi/aic94xx/aic94xx_hwi.c
index 9dda296c0152..b08f0231e562 100644
--- a/drivers/scsi/aic94xx/aic94xx_hwi.c
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.c
@@ -246,7 +246,7 @@ static void asd_get_max_scb_ddb(struct asd_ha_struct 
*asd_ha)
 
 /* ---------- Done List initialization ---------- */
 
-static void asd_dl_tasklet_handler(unsigned long);
+static void asd_dl_work_handler(struct work_struct *);
 
 static int asd_init_dl(struct asd_ha_struct *asd_ha)
 {
@@ -259,8 +259,7 @@ static int asd_init_dl(struct asd_ha_struct *asd_ha)
        asd_ha->seq.dl = asd_ha->seq.actual_dl->vaddr;
        asd_ha->seq.dl_toggle = ASD_DEF_DL_TOGGLE;
        asd_ha->seq.dl_next = 0;
-       tasklet_init(&asd_ha->seq.dl_tasklet, asd_dl_tasklet_handler,
-                    (unsigned long) asd_ha);
+       INIT_WORK(&asd_ha->seq.dl_work, asd_dl_work_handler);
 
        return 0;
 }
@@ -709,10 +708,9 @@ static void asd_chip_reset(struct asd_ha_struct *asd_ha)
 
 /* ---------- Done List Routines ---------- */
 
-static void asd_dl_tasklet_handler(unsigned long data)
+static void asd_dl_work_handler(struct work_struct *t)
 {
-       struct asd_ha_struct *asd_ha = (struct asd_ha_struct *) data;
-       struct asd_seq_data *seq = &asd_ha->seq;
+       struct asd_seq_data *seq = from_work(seq, t, dl_work);
        unsigned long flags;
 
        while (1) {
@@ -739,7 +737,7 @@ static void asd_dl_tasklet_handler(unsigned long data)
                seq->pending--;
                spin_unlock_irqrestore(&seq->pend_q_lock, flags);
        out:
-               ascb->tasklet_complete(ascb, dl);
+               ascb->work_complete(ascb, dl);
 
        next_1:
                seq->dl_next = (seq->dl_next + 1) & (ASD_DL_SIZE-1);
@@ -756,7 +754,7 @@ static void asd_dl_tasklet_handler(unsigned long data)
  */
 static void asd_process_donelist_isr(struct asd_ha_struct *asd_ha)
 {
-       tasklet_schedule(&asd_ha->seq.dl_tasklet);
+       queue_work(system_bh_wq, &asd_ha->seq.dl_work);
 }
 
 /**
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h 
b/drivers/scsi/aic94xx/aic94xx_hwi.h
index 930e192b1cd4..2cc6fb7aa1a7 100644
--- a/drivers/scsi/aic94xx/aic94xx_hwi.h
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.h
@@ -12,6 +12,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
+#include <linux/workqueue.h>
 
 #include <scsi/libsas.h>
 
@@ -117,7 +118,7 @@ struct asd_ascb {
        struct asd_dma_tok dma_scb;
        struct asd_dma_tok *sg_arr;
 
-       void (*tasklet_complete)(struct asd_ascb *, struct done_list_struct *);
+       void (*work_complete)(struct asd_ascb *, struct done_list_struct *);
        u8     uldd_timer:1;
 
        /* internally generated command */
@@ -152,7 +153,7 @@ struct asd_seq_data {
        void *tc_index_bitmap;
        int   tc_index_bitmap_bits;
 
-       struct tasklet_struct dl_tasklet;
+       struct work_struct dl_work;
        struct done_list_struct *dl; /* array of done list entries, equals */
        struct asd_dma_tok *actual_dl; /* actual_dl->vaddr */
        int    dl_toggle;
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c 
b/drivers/scsi/aic94xx/aic94xx_scb.c
index 68214a58b160..256800811553 100644
--- a/drivers/scsi/aic94xx/aic94xx_scb.c
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -64,7 +64,7 @@ static void get_lrate_mode(struct asd_phy *phy, u8 oob_mode)
                phy->sas_phy.oob_mode = SATA_OOB_MODE;
 }
 
-static void asd_phy_event_tasklet(struct asd_ascb *ascb,
+static void asd_phy_event_work(struct asd_ascb *ascb,
                                         struct done_list_struct *dl)
 {
        struct asd_ha_struct *asd_ha = ascb->ha;
@@ -215,7 +215,7 @@ static void asd_deform_port(struct asd_ha_struct *asd_ha, 
struct asd_phy *phy)
        spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags);
 }
 
-static void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
+static void asd_bytes_dmaed_work(struct asd_ascb *ascb,
                                    struct done_list_struct *dl,
                                    int edb_id, int phy_id)
 {
@@ -237,7 +237,7 @@ static void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
        sas_notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED, GFP_ATOMIC);
 }
 
-static void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
+static void asd_link_reset_err_work(struct asd_ascb *ascb,
                                       struct done_list_struct *dl,
                                       int phy_id)
 {
@@ -290,7 +290,7 @@ static void asd_link_reset_err_tasklet(struct asd_ascb 
*ascb,
        ;
 }
 
-static void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb,
+static void asd_primitive_rcvd_work(struct asd_ascb *ascb,
                                       struct done_list_struct *dl,
                                       int phy_id)
 {
@@ -361,7 +361,7 @@ static void asd_primitive_rcvd_tasklet(struct asd_ascb 
*ascb,
  *
  * After an EDB has been invalidated, if all EDBs in this ESCB have been
  * invalidated, the ESCB is posted back to the sequencer.
- * Context is tasklet/IRQ.
+ * Context is BH work/IRQ.
  */
 void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
 {
@@ -396,7 +396,7 @@ void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
        }
 }
 
-static void escb_tasklet_complete(struct asd_ascb *ascb,
+static void escb_work_complete(struct asd_ascb *ascb,
                                  struct done_list_struct *dl)
 {
        struct asd_ha_struct *asd_ha = ascb->ha;
@@ -546,21 +546,21 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
        switch (sb_opcode) {
        case BYTES_DMAED:
                ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __func__, phy_id);
-               asd_bytes_dmaed_tasklet(ascb, dl, edb, phy_id);
+               asd_bytes_dmaed_work(ascb, dl, edb, phy_id);
                break;
        case PRIMITIVE_RECVD:
                ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __func__,
                            phy_id);
-               asd_primitive_rcvd_tasklet(ascb, dl, phy_id);
+               asd_primitive_rcvd_work(ascb, dl, phy_id);
                break;
        case PHY_EVENT:
                ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __func__, phy_id);
-               asd_phy_event_tasklet(ascb, dl);
+               asd_phy_event_work(ascb, dl);
                break;
        case LINK_RESET_ERROR:
                ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __func__,
                            phy_id);
-               asd_link_reset_err_tasklet(ascb, dl, phy_id);
+               asd_link_reset_err_work(ascb, dl, phy_id);
                break;
        case TIMER_EVENT:
                ASD_DPRINTK("%s: phy%d: TIMER_EVENT, lost dw sync\n",
@@ -600,7 +600,7 @@ int asd_init_post_escbs(struct asd_ha_struct *asd_ha)
        int i;
 
        for (i = 0; i < seq->num_escbs; i++)
-               seq->escb_arr[i]->tasklet_complete = escb_tasklet_complete;
+               seq->escb_arr[i]->work_complete = escb_work_complete;
 
        ASD_DPRINTK("posting %d escbs\n", i);
        return asd_post_escb_list(asd_ha, seq->escb_arr[0], seq->num_escbs);
@@ -613,7 +613,7 @@ int asd_init_post_escbs(struct asd_ha_struct *asd_ha)
                            | CURRENT_OOB_ERROR)
 
 /**
- * control_phy_tasklet_complete -- tasklet complete for CONTROL PHY ascb
+ * control_phy_work_complete -- BH work complete for CONTROL PHY ascb
  * @ascb: pointer to an ascb
  * @dl: pointer to the done list entry
  *
@@ -623,7 +623,7 @@ int asd_init_post_escbs(struct asd_ha_struct *asd_ha)
  *  - if a device is connected to the LED, it is lit,
  *  - if no device is connected to the LED, is is dimmed (off).
  */
-static void control_phy_tasklet_complete(struct asd_ascb *ascb,
+static void control_phy_work_complete(struct asd_ascb *ascb,
                                         struct done_list_struct *dl)
 {
        struct asd_ha_struct *asd_ha = ascb->ha;
@@ -758,9 +758,9 @@ static void set_speed_mask(u8 *speed_mask, struct 
asd_phy_desc *pd)
  *
  * This function builds a CONTROL PHY scb.  No allocation of any kind
  * is performed. @ascb is allocated with the list function.
- * The caller can override the ascb->tasklet_complete to point
+ * The caller can override the ascb->work_complete to point
  * to its own callback function.  It must call asd_ascb_free()
- * at its tasklet complete function.
+ * at its BH work complete function.
  * See the default implementation.
  */
 void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc)
@@ -806,14 +806,14 @@ void asd_build_control_phy(struct asd_ascb *ascb, int 
phy_id, u8 subfunc)
 
        control_phy->conn_handle = cpu_to_le16(0xFFFF);
 
-       ascb->tasklet_complete = control_phy_tasklet_complete;
+       ascb->work_complete = control_phy_work_complete;
 }
 
 /* ---------- INITIATE LINK ADM TASK ---------- */
 
 #if 0
 
-static void link_adm_tasklet_complete(struct asd_ascb *ascb,
+static void link_adm_work_complete(struct asd_ascb *ascb,
                                      struct done_list_struct *dl)
 {
        u8 opcode = dl->opcode;
@@ -842,7 +842,7 @@ void asd_build_initiate_link_adm_task(struct asd_ascb 
*ascb, int phy_id,
        link_adm->sub_func = subfunc;
        link_adm->conn_handle = cpu_to_le16(0xFFFF);
 
-       ascb->tasklet_complete = link_adm_tasklet_complete;
+       ascb->work_complete = link_adm_work_complete;
 }
 
 #endif  /*  0  */
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c 
b/drivers/scsi/aic94xx/aic94xx_task.c
index 4bfd03724ad6..2e1e30ba5555 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -138,9 +138,9 @@ static void asd_unmap_scatterlist(struct asd_ascb *ascb)
                             task->num_scatter, task->data_dir);
 }
 
-/* ---------- Task complete tasklet ---------- */
+/* ---------- Task complete BH work ---------- */
 
-static void asd_get_response_tasklet(struct asd_ascb *ascb,
+static void asd_get_response_work(struct asd_ascb *ascb,
                                     struct done_list_struct *dl)
 {
        struct asd_ha_struct *asd_ha = ascb->ha;
@@ -194,7 +194,7 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb,
        asd_invalidate_edb(escb, edb_id);
 }
 
-static void asd_task_tasklet_complete(struct asd_ascb *ascb,
+static void asd_task_work_complete(struct asd_ascb *ascb,
                                      struct done_list_struct *dl)
 {
        struct sas_task *task = ascb->uldd_task;
@@ -224,7 +224,7 @@ static void asd_task_tasklet_complete(struct asd_ascb *ascb,
        case TC_ATA_RESP:
                ts->resp = SAS_TASK_COMPLETE;
                ts->stat = SAS_PROTO_RESPONSE;
-               asd_get_response_tasklet(ascb, dl);
+               asd_get_response_work(ascb, dl);
                break;
        case TF_OPEN_REJECT:
                ts->resp = SAS_TASK_UNDELIVERED;
@@ -392,7 +392,7 @@ static int asd_build_ata_ascb(struct asd_ascb *ascb, struct 
sas_task *task,
 
                scb->ata_task.flags = 0;
        }
-       ascb->tasklet_complete = asd_task_tasklet_complete;
+       ascb->work_complete = asd_task_work_complete;
 
        if (likely(!task->ata_task.device_control_reg_update))
                res = asd_map_scatterlist(task, scb->ata_task.sg_element,
@@ -440,7 +440,7 @@ static int asd_build_smp_ascb(struct asd_ascb *ascb, struct 
sas_task *task,
        scb->smp_task.conn_handle = cpu_to_le16((u16)
                                                (unsigned long)dev->lldd_dev);
 
-       ascb->tasklet_complete = asd_task_tasklet_complete;
+       ascb->work_complete = asd_task_work_complete;
 
        return 0;
 }
@@ -490,7 +490,7 @@ static int asd_build_ssp_ascb(struct asd_ascb *ascb, struct 
sas_task *task,
        scb->ssp_task.data_dir = data_dir_flags[task->data_dir];
        scb->ssp_task.retry_count = scb->ssp_task.retry_count;
 
-       ascb->tasklet_complete = asd_task_tasklet_complete;
+       ascb->work_complete = asd_task_work_complete;
 
        res = asd_map_scatterlist(task, scb->ssp_task.sg_element, gfp_flags);
 
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c 
b/drivers/scsi/aic94xx/aic94xx_tmf.c
index 27d32b8c2987..5eb0cc57ed2a 100644
--- a/drivers/scsi/aic94xx/aic94xx_tmf.c
+++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
@@ -15,13 +15,13 @@
 /* ---------- Internal enqueue ---------- */
 
 static int asd_enqueue_internal(struct asd_ascb *ascb,
-               void (*tasklet_complete)(struct asd_ascb *,
+               void (*work_complete)(struct asd_ascb *,
                                         struct done_list_struct *),
                                void (*timed_out)(struct timer_list *t))
 {
        int res;
 
-       ascb->tasklet_complete = tasklet_complete;
+       ascb->work_complete = work_complete;
        ascb->uldd_timer = 1;
 
        ascb->timer.function = timed_out;
@@ -37,7 +37,7 @@ static int asd_enqueue_internal(struct asd_ascb *ascb,
 
 /* ---------- CLEAR NEXUS ---------- */
 
-struct tasklet_completion_status {
+struct work_completion_status {
        int     dl_opcode;
        int     tmf_state;
        u8      tag_valid:1;
@@ -45,7 +45,7 @@ struct tasklet_completion_status {
 };
 
 #define DECLARE_TCS(tcs) \
-       struct tasklet_completion_status tcs = { \
+       struct work_completion_status tcs = { \
                .dl_opcode = 0, \
                .tmf_state = 0, \
                .tag_valid = 0, \
@@ -53,10 +53,10 @@ struct tasklet_completion_status {
        }
 
 
-static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb,
+static void asd_clear_nexus_work_complete(struct asd_ascb *ascb,
                                             struct done_list_struct *dl)
 {
-       struct tasklet_completion_status *tcs = ascb->uldd_task;
+       struct work_completion_status *tcs = ascb->uldd_task;
        ASD_DPRINTK("%s: here\n", __func__);
        if (!del_timer(&ascb->timer)) {
                ASD_DPRINTK("%s: couldn't delete timer\n", __func__);
@@ -71,7 +71,7 @@ static void asd_clear_nexus_tasklet_complete(struct asd_ascb 
*ascb,
 static void asd_clear_nexus_timedout(struct timer_list *t)
 {
        struct asd_ascb *ascb = from_timer(ascb, t, timer);
-       struct tasklet_completion_status *tcs = ascb->uldd_task;
+       struct work_completion_status *tcs = ascb->uldd_task;
 
        ASD_DPRINTK("%s: here\n", __func__);
        tcs->dl_opcode = TMF_RESP_FUNC_FAILED;
@@ -98,7 +98,7 @@ static void asd_clear_nexus_timedout(struct timer_list *t)
 
 #define CLEAR_NEXUS_POST        \
        ASD_DPRINTK("%s: POST\n", __func__); \
-       res = asd_enqueue_internal(ascb, asd_clear_nexus_tasklet_complete, \
+       res = asd_enqueue_internal(ascb, asd_clear_nexus_work_complete, \
                                   asd_clear_nexus_timedout);              \
        if (res)                \
                goto out_err;   \
@@ -245,14 +245,14 @@ static int asd_clear_nexus_index(struct sas_task *task)
 static void asd_tmf_timedout(struct timer_list *t)
 {
        struct asd_ascb *ascb = from_timer(ascb, t, timer);
-       struct tasklet_completion_status *tcs = ascb->uldd_task;
+       struct work_completion_status *tcs = ascb->uldd_task;
 
        ASD_DPRINTK("tmf timed out\n");
        tcs->tmf_state = TMF_RESP_FUNC_FAILED;
        complete(ascb->completion);
 }
 
-static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb,
+static int asd_get_tmf_resp_work(struct asd_ascb *ascb,
                                    struct done_list_struct *dl)
 {
        struct asd_ha_struct *asd_ha = ascb->ha;
@@ -270,7 +270,7 @@ static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb,
        struct ssp_response_iu   *ru;
        int res = TMF_RESP_FUNC_FAILED;
 
-       ASD_DPRINTK("tmf resp tasklet\n");
+       ASD_DPRINTK("tmf resp BH work\n");
 
        spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags);
        escb = asd_tc_index_find(&asd_ha->seq,
@@ -298,21 +298,21 @@ static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb,
        return res;
 }
 
-static void asd_tmf_tasklet_complete(struct asd_ascb *ascb,
+static void asd_tmf_work_complete(struct asd_ascb *ascb,
                                     struct done_list_struct *dl)
 {
-       struct tasklet_completion_status *tcs;
+       struct work_completion_status *tcs;
 
        if (!del_timer(&ascb->timer))
                return;
 
        tcs = ascb->uldd_task;
-       ASD_DPRINTK("tmf tasklet complete\n");
+       ASD_DPRINTK("tmf BH work complete\n");
 
        tcs->dl_opcode = dl->opcode;
 
        if (dl->opcode == TC_SSP_RESP) {
-               tcs->tmf_state = asd_get_tmf_resp_tasklet(ascb, dl);
+               tcs->tmf_state = asd_get_tmf_resp_work(ascb, dl);
                tcs->tag_valid = ascb->tag_valid;
                tcs->tag = ascb->tag;
        }
@@ -452,7 +452,7 @@ int asd_abort_task(struct sas_task *task)
        scb->abort_task.index = cpu_to_le16((u16)tascb->tc_index);
        scb->abort_task.itnl_to = cpu_to_le16(ITNL_TIMEOUT_CONST);
 
-       res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete,
+       res = asd_enqueue_internal(ascb, asd_tmf_work_complete,
                                   asd_tmf_timedout);
        if (res)
                goto out_free;
@@ -600,7 +600,7 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, 
u8 *lun,
        if (tmf == TMF_QUERY_TASK)
                scb->ssp_tmf.index = cpu_to_le16(index);
 
-       res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete,
+       res = asd_enqueue_internal(ascb, asd_tmf_work_complete,
                                   asd_tmf_timedout);
        if (res)
                goto out_err;
diff --git a/drivers/scsi/esas2r/esas2r.h b/drivers/scsi/esas2r/esas2r.h
index ed63f7a9ea54..7c9db9e80576 100644
--- a/drivers/scsi/esas2r/esas2r.h
+++ b/drivers/scsi/esas2r/esas2r.h
@@ -900,7 +900,7 @@ struct esas2r_adapter {
        struct esas2r_flash_context flash_context;
        u32 num_targets_backend;
        u32 ioctl_tunnel;
-       struct tasklet_struct tasklet;
+       struct work_struct work;
        struct pci_dev *pcid;
        struct Scsi_Host *host;
        unsigned int index;
@@ -992,7 +992,7 @@ int esas2r_write_vda(struct esas2r_adapter *a, const char 
*buf, long off,
 int esas2r_read_fs(struct esas2r_adapter *a, char *buf, long off, int count);
 int esas2r_write_fs(struct esas2r_adapter *a, const char *buf, long off,
                    int count);
-void esas2r_adapter_tasklet(unsigned long context);
+void esas2r_adapter_work(struct work_struct *work);
 irqreturn_t esas2r_interrupt(int irq, void *dev_id);
 irqreturn_t esas2r_msi_interrupt(int irq, void *dev_id);
 void esas2r_kickoff_timer(struct esas2r_adapter *a);
@@ -1022,7 +1022,7 @@ bool esas2r_init_adapter_hw(struct esas2r_adapter *a, 
bool init_poll);
 void esas2r_start_request(struct esas2r_adapter *a, struct esas2r_request *rq);
 bool esas2r_send_task_mgmt(struct esas2r_adapter *a,
                           struct esas2r_request *rqaux, u8 task_mgt_func);
-void esas2r_do_tasklet_tasks(struct esas2r_adapter *a);
+void esas2r_do_work_tasks(struct esas2r_adapter *a);
 void esas2r_adapter_interrupt(struct esas2r_adapter *a);
 void esas2r_do_deferred_processes(struct esas2r_adapter *a);
 void esas2r_reset_bus(struct esas2r_adapter *a);
@@ -1283,7 +1283,7 @@ static inline void esas2r_rq_destroy_request(struct 
esas2r_request *rq,
        rq->data_buf = NULL;
 }
 
-static inline bool esas2r_is_tasklet_pending(struct esas2r_adapter *a)
+static inline bool esas2r_is_work_pending(struct esas2r_adapter *a)
 {
 
        return test_bit(AF_BUSRST_NEEDED, &a->flags) ||
@@ -1327,11 +1327,11 @@ static inline void esas2r_enable_chip_interrupts(struct 
esas2r_adapter *a)
 /* Schedule a TASKLET to perform non-interrupt tasks that may require delays
  * or long completion times.
  */
-static inline void esas2r_schedule_tasklet(struct esas2r_adapter *a)
+static inline void esas2r_schedule_work(struct esas2r_adapter *a)
 {
        /* make sure we don't schedule twice */
        if (!test_and_set_bit(AF_TASKLET_SCHEDULED, &a->flags))
-               tasklet_hi_schedule(&a->tasklet);
+               queue_work(system_bh_highpri_wq, &a->work);
 }
 
 static inline void esas2r_enable_heartbeat(struct esas2r_adapter *a)
diff --git a/drivers/scsi/esas2r/esas2r_init.c 
b/drivers/scsi/esas2r/esas2r_init.c
index c1a5ab662dc8..cf149a69ec55 100644
--- a/drivers/scsi/esas2r/esas2r_init.c
+++ b/drivers/scsi/esas2r/esas2r_init.c
@@ -401,9 +401,7 @@ int esas2r_init_adapter(struct Scsi_Host *host, struct 
pci_dev *pcid,
                return 0;
        }
 
-       tasklet_init(&a->tasklet,
-                    esas2r_adapter_tasklet,
-                    (unsigned long)a);
+       INIT_WORK(&a->work, esas2r_adapter_work);
 
        /*
         * Disable chip interrupts to prevent spurious interrupts
@@ -441,7 +439,7 @@ static void esas2r_adapter_power_down(struct esas2r_adapter 
*a,
            &&  (!test_bit(AF_DEGRADED_MODE, &a->flags))) {
                if (!power_management) {
                        del_timer_sync(&a->timer);
-                       tasklet_kill(&a->tasklet);
+                       cancel_work_sync(&a->work);
                }
                esas2r_power_down(a);
 
@@ -1346,7 +1344,7 @@ bool esas2r_init_adapter_hw(struct esas2r_adapter *a, 
bool init_poll)
                u32 deltatime;
 
                /*
-                * Block Tasklets from getting scheduled and indicate this is
+                * Block Works from getting scheduled and indicate this is
                 * polled discovery.
                 */
                set_bit(AF_TASKLET_SCHEDULED, &a->flags);
@@ -1394,8 +1392,8 @@ bool esas2r_init_adapter_hw(struct esas2r_adapter *a, 
bool init_poll)
                                nexttick -= deltatime;
 
                        /* Do any deferred processing */
-                       if (esas2r_is_tasklet_pending(a))
-                               esas2r_do_tasklet_tasks(a);
+                       if (esas2r_is_work_pending(a))
+                               esas2r_do_work_tasks(a);
 
                }
 
@@ -1463,7 +1461,7 @@ void esas2r_reset_adapter(struct esas2r_adapter *a)
 {
        set_bit(AF_OS_RESET, &a->flags);
        esas2r_local_reset_adapter(a);
-       esas2r_schedule_tasklet(a);
+       esas2r_schedule_work(a);
 }
 
 void esas2r_reset_chip(struct esas2r_adapter *a)
diff --git a/drivers/scsi/esas2r/esas2r_int.c b/drivers/scsi/esas2r/esas2r_int.c
index 5281d9356327..54e6eea522f8 100644
--- a/drivers/scsi/esas2r/esas2r_int.c
+++ b/drivers/scsi/esas2r/esas2r_int.c
@@ -97,7 +97,7 @@ irqreturn_t esas2r_interrupt(int irq, void *dev_id)
                return IRQ_NONE;
 
        set_bit(AF2_INT_PENDING, &a->flags2);
-       esas2r_schedule_tasklet(a);
+       esas2r_schedule_work(a);
 
        return IRQ_HANDLED;
 }
@@ -162,7 +162,7 @@ irqreturn_t esas2r_msi_interrupt(int irq, void *dev_id)
        if (likely(atomic_read(&a->disable_cnt) == 0))
                esas2r_do_deferred_processes(a);
 
-       esas2r_do_tasklet_tasks(a);
+       esas2r_do_work_tasks(a);
 
        return 1;
 }
@@ -327,8 +327,8 @@ void esas2r_do_deferred_processes(struct esas2r_adapter *a)
 
        /* Clear off the completed list to be processed later. */
 
-       if (esas2r_is_tasklet_pending(a)) {
-               esas2r_schedule_tasklet(a);
+       if (esas2r_is_work_pending(a)) {
+               esas2r_schedule_work(a);
 
                startreqs = 0;
        }
@@ -476,7 +476,7 @@ static void esas2r_process_bus_reset(struct esas2r_adapter 
*a)
        esas2r_trace_exit();
 }
 
-static void esas2r_chip_rst_needed_during_tasklet(struct esas2r_adapter *a)
+static void esas2r_chip_rst_needed_during_work(struct esas2r_adapter *a)
 {
 
        clear_bit(AF_CHPRST_NEEDED, &a->flags);
@@ -558,7 +558,7 @@ static void esas2r_chip_rst_needed_during_tasklet(struct 
esas2r_adapter *a)
        }
 }
 
-static void esas2r_handle_chip_rst_during_tasklet(struct esas2r_adapter *a)
+static void esas2r_handle_chip_rst_during_work(struct esas2r_adapter *a)
 {
        while (test_bit(AF_CHPRST_DETECTED, &a->flags)) {
                /*
@@ -614,15 +614,15 @@ static void esas2r_handle_chip_rst_during_tasklet(struct 
esas2r_adapter *a)
 
 
 /* Perform deferred tasks when chip interrupts are disabled */
-void esas2r_do_tasklet_tasks(struct esas2r_adapter *a)
+void esas2r_do_work_tasks(struct esas2r_adapter *a)
 {
 
        if (test_bit(AF_CHPRST_NEEDED, &a->flags) ||
            test_bit(AF_CHPRST_DETECTED, &a->flags)) {
                if (test_bit(AF_CHPRST_NEEDED, &a->flags))
-                       esas2r_chip_rst_needed_during_tasklet(a);
+                       esas2r_chip_rst_needed_during_work(a);
 
-               esas2r_handle_chip_rst_during_tasklet(a);
+               esas2r_handle_chip_rst_during_work(a);
        }
 
        if (test_bit(AF_BUSRST_NEEDED, &a->flags)) {
diff --git a/drivers/scsi/esas2r/esas2r_io.c b/drivers/scsi/esas2r/esas2r_io.c
index a8df916cd57a..d45e6e16a858 100644
--- a/drivers/scsi/esas2r/esas2r_io.c
+++ b/drivers/scsi/esas2r/esas2r_io.c
@@ -851,7 +851,7 @@ void esas2r_reset_bus(struct esas2r_adapter *a)
                set_bit(AF_BUSRST_PENDING, &a->flags);
                set_bit(AF_OS_RESET, &a->flags);
 
-               esas2r_schedule_tasklet(a);
+               esas2r_schedule_work(a);
        }
 }
 
diff --git a/drivers/scsi/esas2r/esas2r_main.c 
b/drivers/scsi/esas2r/esas2r_main.c
index f700a16cd885..e4e378adf7ed 100644
--- a/drivers/scsi/esas2r/esas2r_main.c
+++ b/drivers/scsi/esas2r/esas2r_main.c
@@ -1543,10 +1543,10 @@ void esas2r_complete_request_cb(struct esas2r_adapter 
*a,
        esas2r_free_request(a, rq);
 }
 
-/* Run tasklet to handle stuff outside of interrupt context. */
-void esas2r_adapter_tasklet(unsigned long context)
+/* Run BH work to handle stuff outside of interrupt context. */
+void esas2r_adapter_work(struct work_struct *t)
 {
-       struct esas2r_adapter *a = (struct esas2r_adapter *)context;
+       struct esas2r_adapter *a = from_work(a, t, work);
 
        if (unlikely(test_bit(AF2_TIMER_TICK, &a->flags2))) {
                clear_bit(AF2_TIMER_TICK, &a->flags2);
@@ -1558,14 +1558,14 @@ void esas2r_adapter_tasklet(unsigned long context)
                esas2r_adapter_interrupt(a);
        }
 
-       if (esas2r_is_tasklet_pending(a))
-               esas2r_do_tasklet_tasks(a);
+       if (esas2r_is_work_pending(a))
+               esas2r_do_work_tasks(a);
 
-       if (esas2r_is_tasklet_pending(a)
+       if (esas2r_is_work_pending(a)
            || (test_bit(AF2_INT_PENDING, &a->flags2))
            || (test_bit(AF2_TIMER_TICK, &a->flags2))) {
                clear_bit(AF_TASKLET_SCHEDULED, &a->flags);
-               esas2r_schedule_tasklet(a);
+               esas2r_schedule_work(a);
        } else {
                clear_bit(AF_TASKLET_SCHEDULED, &a->flags);
        }
@@ -1589,7 +1589,7 @@ static void esas2r_timer_callback(struct timer_list *t)
 
        set_bit(AF2_TIMER_TICK, &a->flags2);
 
-       esas2r_schedule_tasklet(a);
+       esas2r_schedule_work(a);
 
        esas2r_kickoff_timer(a);
 }
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 05b126bfd18b..6a8ecd3358c4 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -899,7 +899,7 @@ static void ibmvfc_release_crq_queue(struct ibmvfc_host 
*vhost)
 
        ibmvfc_dbg(vhost, "Releasing CRQ\n");
        free_irq(vdev->irq, vhost);
-       tasklet_kill(&vhost->tasklet);
+       cancel_work_sync(&vhost->work);
        do {
                if (rc)
                        msleep(100);
@@ -3767,21 +3767,21 @@ static irqreturn_t ibmvfc_interrupt(int irq, void 
*dev_instance)
 
        spin_lock_irqsave(vhost->host->host_lock, flags);
        vio_disable_interrupts(to_vio_dev(vhost->dev));
-       tasklet_schedule(&vhost->tasklet);
+       queue_work(system_bh_wq, &vhost->work);
        spin_unlock_irqrestore(vhost->host->host_lock, flags);
        return IRQ_HANDLED;
 }
 
 /**
- * ibmvfc_tasklet - Interrupt handler tasklet
+ * ibmvfc_work - Interrupt handler work
  * @data:              ibmvfc host struct
  *
  * Returns:
  *     Nothing
  **/
-static void ibmvfc_tasklet(void *data)
+static void ibmvfc_work(struct work_struct *t)
 {
-       struct ibmvfc_host *vhost = data;
+       struct ibmvfc_host *vhost = from_work(vhost, t, work);
        struct vio_dev *vdev = to_vio_dev(vhost->dev);
        struct ibmvfc_crq *crq;
        struct ibmvfc_async_crq *async;
@@ -5885,7 +5885,7 @@ static int ibmvfc_init_crq(struct ibmvfc_host *vhost)
 
        retrc = 0;
 
-       tasklet_init(&vhost->tasklet, (void *)ibmvfc_tasklet, (unsigned 
long)vhost);
+       INIT_WORK(&vhost->work, ibmvfc_work);
 
        if ((rc = request_irq(vdev->irq, ibmvfc_interrupt, 0, IBMVFC_NAME, 
vhost))) {
                dev_err(dev, "Couldn't register irq 0x%x. rc=%d\n", vdev->irq, 
rc);
@@ -5901,7 +5901,7 @@ static int ibmvfc_init_crq(struct ibmvfc_host *vhost)
        return retrc;
 
 req_irq_failed:
-       tasklet_kill(&vhost->tasklet);
+       cancel_work_sync(&vhost->work);
        do {
                rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
        } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
@@ -6474,7 +6474,7 @@ static int ibmvfc_resume(struct device *dev)
 
        spin_lock_irqsave(vhost->host->host_lock, flags);
        vio_disable_interrupts(vdev);
-       tasklet_schedule(&vhost->tasklet);
+       queue_work(system_bh_wq, &vhost->work);
        spin_unlock_irqrestore(vhost->host->host_lock, flags);
        return 0;
 }
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index 745ad5ac7251..42861ee62bf9 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -12,6 +12,7 @@
 
 #include <linux/list.h>
 #include <linux/types.h>
+#include <linux/workqueue.h>
 #include <scsi/viosrp.h>
 
 #define IBMVFC_NAME    "ibmvfc"
@@ -910,7 +911,7 @@ struct ibmvfc_host {
        char partition_name[97];
        void (*job_step) (struct ibmvfc_host *);
        struct task_struct *work_thread;
-       struct tasklet_struct tasklet;
+       struct work_struct work;
        struct work_struct rport_add_work_q;
        wait_queue_head_t init_wait_q;
        wait_queue_head_t work_wait_q;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 71f3e9563520..91e1600bf219 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -125,7 +125,7 @@ static irqreturn_t ibmvscsi_handle_event(int irq, void 
*dev_instance)
        struct ibmvscsi_host_data *hostdata =
            (struct ibmvscsi_host_data *)dev_instance;
        vio_disable_interrupts(to_vio_dev(hostdata->dev));
-       tasklet_schedule(&hostdata->srp_task);
+       queue_work(system_bh_wq, &hostdata->srp_task);
        return IRQ_HANDLED;
 }
 
@@ -145,7 +145,7 @@ static void ibmvscsi_release_crq_queue(struct crq_queue 
*queue,
        long rc = 0;
        struct vio_dev *vdev = to_vio_dev(hostdata->dev);
        free_irq(vdev->irq, (void *)hostdata);
-       tasklet_kill(&hostdata->srp_task);
+       cancel_work_sync(&hostdata->srp_task);
        do {
                if (rc)
                        msleep(100);
@@ -367,8 +367,7 @@ static int ibmvscsi_init_crq_queue(struct crq_queue *queue,
        queue->cur = 0;
        spin_lock_init(&queue->lock);
 
-       tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task,
-                    (unsigned long)hostdata);
+       INIT_WORK(&hostdata->srp_task, ibmvscsi_work);
 
        if (request_irq(vdev->irq,
                        ibmvscsi_handle_event,
@@ -387,7 +386,7 @@ static int ibmvscsi_init_crq_queue(struct crq_queue *queue,
        return retrc;
 
       req_irq_failed:
-       tasklet_kill(&hostdata->srp_task);
+       cancel_work_sync(&hostdata->srp_task);
        rc = 0;
        do {
                if (rc)
@@ -2194,9 +2193,10 @@ static int ibmvscsi_work_to_do(struct ibmvscsi_host_data 
*hostdata)
        return rc;
 }
 
-static int ibmvscsi_work(void *data)
+static int ibmvscsi_work(struct work_struct *t)
 {
-       struct ibmvscsi_host_data *hostdata = data;
+       struct ibmvscsi_host_data *hostdata =
+               from_work(hostdata, t, srp_task);
        int rc;
 
        set_user_nice(current, MIN_NICE);
@@ -2371,7 +2371,7 @@ static int ibmvscsi_resume(struct device *dev)
 {
        struct ibmvscsi_host_data *hostdata = dev_get_drvdata(dev);
        vio_disable_interrupts(to_vio_dev(hostdata->dev));
-       tasklet_schedule(&hostdata->srp_task);
+       queue_work(system_bh_wq, &hostdata->srp_task);
 
        return 0;
 }
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index e60916ef7a49..cfc0a70c434c 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -19,6 +19,7 @@
 #include <linux/list.h>
 #include <linux/completion.h>
 #include <linux/interrupt.h>
+#include <linux/workqueue.h>
 #include <scsi/viosrp.h>
 
 struct scsi_cmnd;
@@ -90,7 +91,7 @@ struct ibmvscsi_host_data {
        struct device *dev;
        struct event_pool pool;
        struct crq_queue queue;
-       struct tasklet_struct srp_task;
+       struct work_struct srp_task;
        struct list_head sent;
        struct Scsi_Host *host;
        struct task_struct *work_thread;
diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c 
b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
index 68b99924ee4f..204975fb61ba 100644
--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
+++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
@@ -2948,7 +2948,7 @@ static irqreturn_t ibmvscsis_interrupt(int dummy, void 
*data)
        struct scsi_info *vscsi = data;
 
        vio_disable_interrupts(vscsi->dma_dev);
-       tasklet_schedule(&vscsi->work_task);
+       queue_work(system_bh_wq, &scsi->work_task);
 
        return IRQ_HANDLED;
 }
@@ -3309,7 +3309,7 @@ static int ibmvscsis_rdma(struct ibmvscsis_cmd *cmd, 
struct scatterlist *sg,
 
 /**
  * ibmvscsis_handle_crq() - Handle CRQ
- * @data:      Pointer to our adapter structure
+ * @t: Pointer to work_struct
  *
  * Read the command elements from the command queue and copy the payloads
  * associated with the command elements to local memory and execute the
@@ -3317,9 +3317,9 @@ static int ibmvscsis_rdma(struct ibmvscsis_cmd *cmd, 
struct scatterlist *sg,
  *
  * Note: this is an edge triggered interrupt. It can not be shared.
  */
-static void ibmvscsis_handle_crq(unsigned long data)
+static void ibmvscsis_handle_crq(struct work_struct *t)
 {
-       struct scsi_info *vscsi = (struct scsi_info *)data;
+       struct scsi_info *vscsi = from_work(scsi, t, work_task);
        struct viosrp_crq *crq;
        long rc;
        bool ack = true;
@@ -3530,8 +3530,7 @@ static int ibmvscsis_probe(struct vio_dev *vdev,
        dev_dbg(&vscsi->dev, "probe hrc %ld, client partition num %d\n",
                hrc, vscsi->client_data.partition_number);
 
-       tasklet_init(&vscsi->work_task, ibmvscsis_handle_crq,
-                    (unsigned long)vscsi);
+       INIT_WORK(&vscsi->work_task, ibmvscsis_handle_crq);
 
        init_completion(&vscsi->wait_idle);
        init_completion(&vscsi->unconfig);
@@ -3565,7 +3564,7 @@ static int ibmvscsis_probe(struct vio_dev *vdev,
 free_buf:
        kfree(vscsi->map_buf);
 destroy_queue:
-       tasklet_kill(&vscsi->work_task);
+       cancel_work_sync(&vscsi->work_task);
        ibmvscsis_unregister_command_q(vscsi);
        ibmvscsis_destroy_command_q(vscsi);
 free_timer:
@@ -3602,7 +3601,7 @@ static void ibmvscsis_remove(struct vio_dev *vdev)
        dma_unmap_single(&vdev->dev, vscsi->map_ioba, PAGE_SIZE,
                         DMA_BIDIRECTIONAL);
        kfree(vscsi->map_buf);
-       tasklet_kill(&vscsi->work_task);
+       cancel_work_sync(&vscsi->work_task);
        ibmvscsis_destroy_command_q(vscsi);
        ibmvscsis_freetimer(vscsi);
        ibmvscsis_free_cmds(vscsi);
diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h 
b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
index 7ae074e5d7a1..e7dea32e4dbc 100644
--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
+++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
@@ -18,6 +18,7 @@
 #define __H_IBMVSCSI_TGT
 
 #include <linux/interrupt.h>
+#include <linux/workqueue.h>
 #include "libsrp.h"
 
 #define SYS_ID_NAME_LEN                64
@@ -295,7 +296,7 @@ struct scsi_info {
        struct vio_dev *dma_dev;
        struct srp_target target;
        struct ibmvscsis_tport tport;
-       struct tasklet_struct work_task;
+       struct work_struct work_task;
        struct work_struct proc_work;
 };
 
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 35589b6af90d..d911dc159809 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -220,7 +220,7 @@ irqreturn_t isci_msix_isr(int vec, void *data)
        struct isci_host *ihost = data;
 
        if (sci_controller_isr(ihost))
-               tasklet_schedule(&ihost->completion_tasklet);
+               queue_work(system_bh_wq, &ihost->completion_work);
 
        return IRQ_HANDLED;
 }
@@ -610,7 +610,7 @@ irqreturn_t isci_intx_isr(int vec, void *data)
 
        if (sci_controller_isr(ihost)) {
                writel(SMU_ISR_COMPLETION, 
&ihost->smu_registers->interrupt_status);
-               tasklet_schedule(&ihost->completion_tasklet);
+               queue_work(system_bh_wq, &ihost->completion_work);
                ret = IRQ_HANDLED;
        } else if (sci_controller_error_isr(ihost)) {
                spin_lock(&ihost->scic_lock);
@@ -1106,14 +1106,14 @@ void ireq_done(struct isci_host *ihost, struct 
isci_request *ireq, struct sas_ta
 /**
  * isci_host_completion_routine() - This function is the delayed service
  *    routine that calls the sci core library's completion handler. It's
- *    scheduled as a tasklet from the interrupt service routine when interrupts
+ *    scheduled as a BH work from the interrupt service routine when interrupts
  *    in use, or set as the timeout function in polled mode.
- * @data: This parameter specifies the ISCI host object
+ * @t: pointer to the work_struct
  *
  */
-void isci_host_completion_routine(unsigned long data)
+void isci_host_completion_routine(struct work_struct *t)
 {
-       struct isci_host *ihost = (struct isci_host *)data;
+       struct isci_host *ihost = from_work(ihost, t, completion_work);
        u16 active;
 
        spin_lock_irq(&ihost->scic_lock);
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 52388374cf31..8350e70bfb3a 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -131,8 +131,8 @@ struct sci_port_configuration_agent {
  * @device_table: rni (hw remote node index) to remote device lookup table
  * @available_remote_nodes: rni allocator
  * @power_control: manage device spin up
- * @io_request_sequence: generation number for tci's (task contexts)
- * @task_context_table: hw task context table
+ * @io_request_sequence: generation number for tci's (bh contexts)
+ * @task_context_table: hw bh context table
  * @remote_node_context_table: hw remote node context table
  * @completion_queue: hw-producer driver-consumer communication ring
  * @completion_queue_get: tracks the driver 'head' of the ring to notify hw
@@ -203,7 +203,7 @@ struct isci_host {
        #define IHOST_IRQ_ENABLED 2
        unsigned long flags;
        wait_queue_head_t eventq;
-       struct tasklet_struct completion_tasklet;
+       struct work_struct completion_work;
        spinlock_t scic_lock;
        struct isci_request *reqs[SCI_MAX_IO_REQUESTS];
        struct isci_remote_device devices[SCI_MAX_REMOTE_DEVICES];
@@ -478,7 +478,7 @@ void isci_tci_free(struct isci_host *ihost, u16 tci);
 void ireq_done(struct isci_host *ihost, struct isci_request *ireq, struct 
sas_task *task);
 
 int isci_host_init(struct isci_host *);
-void isci_host_completion_routine(unsigned long data);
+void isci_host_completion_routine(struct work_struct *t);
 void isci_host_deinit(struct isci_host *);
 void sci_controller_disable_interrupts(struct isci_host *ihost);
 bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost);
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index c582a3932cea..605e4d965e04 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -510,8 +510,8 @@ static struct isci_host *isci_host_alloc(struct pci_dev 
*pdev, int id)
        init_waitqueue_head(&ihost->eventq);
        ihost->sas_ha.dev = &ihost->pdev->dev;
        ihost->sas_ha.lldd_ha = ihost;
-       tasklet_init(&ihost->completion_tasklet,
-                    isci_host_completion_routine, (unsigned long)ihost);
+       INIT_WORK(&ihost->completion_work,
+                    isci_host_completion_routine);
 
        /* validate module parameters */
        /* TODO: kill struct sci_user_parameters and reference directly */
diff --git a/drivers/scsi/megaraid/mega_common.h 
b/drivers/scsi/megaraid/mega_common.h
index 2ad0aa2f837d..cff3e98dbe31 100644
--- a/drivers/scsi/megaraid/mega_common.h
+++ b/drivers/scsi/megaraid/mega_common.h
@@ -24,6 +24,7 @@
 #include <linux/list.h>
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
+#include <linux/workqueue.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
@@ -95,7 +96,7 @@ typedef struct {
 
 /**
  * struct adapter_t - driver's initialization structure
- * @aram dpc_h                 : tasklet handle
+ * @aram dpc_h                 : work handle
  * @pdev                       : pci configuration pointer for kernel
  * @host                       : pointer to host structure of mid-layer
  * @lock                       : synchronization lock for mid-layer and driver
@@ -149,7 +150,7 @@ typedef struct {
 #define VERSION_SIZE   16
 
 typedef struct {
-       struct tasklet_struct   dpc_h;
+       struct work_struct      dpc_h;
        struct pci_dev          *pdev;
        struct Scsi_Host        *host;
        spinlock_t              lock;
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c 
b/drivers/scsi/megaraid/megaraid_mbox.c
index bc867da650b6..4ce033cb9554 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -119,7 +119,7 @@ static void megaraid_mbox_prepare_epthru(adapter_t *, scb_t 
*,
 
 static irqreturn_t megaraid_isr(int, void *);
 
-static void megaraid_mbox_dpc(unsigned long);
+static void megaraid_mbox_dpc(struct work_struct *);
 
 static ssize_t megaraid_mbox_app_hndl_show(struct device *, struct 
device_attribute *attr, char *);
 static ssize_t megaraid_mbox_ld_show(struct device *, struct device_attribute 
*attr, char *);
@@ -879,9 +879,8 @@ megaraid_init_mbox(adapter_t *adapter)
                }
        }
 
-       // setup tasklet for DPC
-       tasklet_init(&adapter->dpc_h, megaraid_mbox_dpc,
-                       (unsigned long)adapter);
+       /* Initialize the work for DPC */
+       INIT_WORK(&adapter->dpc_h, megaraid_mbox_dpc);
 
        con_log(CL_DLEVEL1, (KERN_INFO
                "megaraid mbox hba successfully initialized\n"));
@@ -917,7 +916,7 @@ megaraid_fini_mbox(adapter_t *adapter)
        // flush all caches
        megaraid_mbox_flush_cache(adapter);
 
-       tasklet_kill(&adapter->dpc_h);
+       cancel_work_sync(&adapter->dpc_h);
 
        megaraid_sysfs_free_resources(adapter);
 
@@ -2127,7 +2126,7 @@ megaraid_ack_sequence(adapter_t *adapter)
 
        // schedule the DPC if there is some work for it
        if (handled)
-               tasklet_schedule(&adapter->dpc_h);
+               queue_work(system_bh_wq, &adapter->dpc_h);
 
        return handled;
 }
@@ -2158,17 +2157,17 @@ megaraid_isr(int irq, void *devp)
 
 
 /**
- * megaraid_mbox_dpc - the tasklet to complete the commands from completed list
- * @devp       : pointer to HBA soft state
+ * megaraid_mbox_dpc - the work handler to complete the commands from 
completed list
+ * @t  : pointer to work_struct
  *
  * Pick up the commands from the completed list and send back to the owners.
  * This is a reentrant function and does not assume any locks are held while
  * it is being called.
  */
 static void
-megaraid_mbox_dpc(unsigned long devp)
+megaraid_mbox_dpc(struct work_struct *t)
 {
-       adapter_t               *adapter = (adapter_t *)devp;
+       adapter_t               *adapter = from_work(adapter, t, dpc_h);
        mraid_device_t          *raid_dev;
        struct list_head        clist;
        struct scatterlist      *sgl;
@@ -3812,7 +3811,7 @@ megaraid_sysfs_free_resources(adapter_t *adapter)
  * megaraid_sysfs_get_ldmap_done - callback for get ldmap
  * @uioc       : completed packet
  *
- * Callback routine called in the ISR/tasklet context for get ldmap call
+ * Callback routine called in the ISR/BH context for get ldmap call
  */
 static void
 megaraid_sysfs_get_ldmap_done(uioc_t *uioc)
diff --git a/drivers/scsi/megaraid/megaraid_sas.h 
b/drivers/scsi/megaraid/megaraid_sas.h
index 56624cbf7fa5..8de7a678e096 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -2389,7 +2389,7 @@ struct megasas_instance {
        atomic64_t high_iops_outstanding;
 
        struct megasas_instance_template *instancet;
-       struct tasklet_struct isr_tasklet;
+       struct work_struct isr_work;
        struct work_struct work_init;
        struct delayed_work fw_fault_work;
        struct workqueue_struct *fw_fault_work_q;
@@ -2551,7 +2551,7 @@ struct megasas_instance_template {
        int (*check_reset)(struct megasas_instance *, \
                struct megasas_register_set __iomem *);
        irqreturn_t (*service_isr)(int irq, void *devp);
-       void (*tasklet)(unsigned long);
+       void (*work)(struct work_struct *);
        u32 (*init_adapter)(struct megasas_instance *);
        u32 (*build_and_issue_cmd) (struct megasas_instance *,
                                    struct scsi_cmnd *);
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c 
b/drivers/scsi/megaraid/megaraid_sas_base.c
index 3d4f13da1ae8..dd935943ae4f 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -234,7 +234,7 @@ megasas_init_adapter_mfi(struct megasas_instance *instance);
 u32
 megasas_build_and_issue_cmd(struct megasas_instance *instance,
                            struct scsi_cmnd *scmd);
-static void megasas_complete_cmd_dpc(unsigned long instance_addr);
+static void megasas_complete_cmd_dpc(struct work_struct *t);
 int
 wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
        int seconds);
@@ -615,7 +615,7 @@ static struct megasas_instance_template 
megasas_instance_template_xscale = {
        .adp_reset = megasas_adp_reset_xscale,
        .check_reset = megasas_check_reset_xscale,
        .service_isr = megasas_isr,
-       .tasklet = megasas_complete_cmd_dpc,
+       .work = megasas_complete_cmd_dpc,
        .init_adapter = megasas_init_adapter_mfi,
        .build_and_issue_cmd = megasas_build_and_issue_cmd,
        .issue_dcmd = megasas_issue_dcmd,
@@ -754,7 +754,7 @@ static struct megasas_instance_template 
megasas_instance_template_ppc = {
        .adp_reset = megasas_adp_reset_xscale,
        .check_reset = megasas_check_reset_ppc,
        .service_isr = megasas_isr,
-       .tasklet = megasas_complete_cmd_dpc,
+       .work = megasas_complete_cmd_dpc,
        .init_adapter = megasas_init_adapter_mfi,
        .build_and_issue_cmd = megasas_build_and_issue_cmd,
        .issue_dcmd = megasas_issue_dcmd,
@@ -895,7 +895,7 @@ static struct megasas_instance_template 
megasas_instance_template_skinny = {
        .adp_reset = megasas_adp_reset_gen2,
        .check_reset = megasas_check_reset_skinny,
        .service_isr = megasas_isr,
-       .tasklet = megasas_complete_cmd_dpc,
+       .work = megasas_complete_cmd_dpc,
        .init_adapter = megasas_init_adapter_mfi,
        .build_and_issue_cmd = megasas_build_and_issue_cmd,
        .issue_dcmd = megasas_issue_dcmd,
@@ -1095,7 +1095,7 @@ static struct megasas_instance_template 
megasas_instance_template_gen2 = {
        .adp_reset = megasas_adp_reset_gen2,
        .check_reset = megasas_check_reset_gen2,
        .service_isr = megasas_isr,
-       .tasklet = megasas_complete_cmd_dpc,
+       .work = megasas_complete_cmd_dpc,
        .init_adapter = megasas_init_adapter_mfi,
        .build_and_issue_cmd = megasas_build_and_issue_cmd,
        .issue_dcmd = megasas_issue_dcmd,
@@ -2269,18 +2269,18 @@ megasas_check_and_restore_queue_depth(struct 
megasas_instance *instance)
 
 /**
  * megasas_complete_cmd_dpc     -      Returns FW's controller structure
- * @instance_addr:                     Address of adapter soft state
+ * @t:                                 pointer to the work_struct
  *
- * Tasklet to complete cmds
+ * Work to complete cmds
  */
-static void megasas_complete_cmd_dpc(unsigned long instance_addr)
+static void megasas_complete_cmd_dpc(struct work_struct *t)
 {
        u32 producer;
        u32 consumer;
        u32 context;
        struct megasas_cmd *cmd;
        struct megasas_instance *instance =
-                               (struct megasas_instance *)instance_addr;
+                               from_work(instance, t, isr_work);
        unsigned long flags;
 
        /* If we have already declared adapter dead, donot complete cmds */
@@ -2825,7 +2825,7 @@ static int megasas_wait_for_outstanding(struct 
megasas_instance *instance)
                         * Call cmd completion routine. Cmd to be
                         * be completed directly without depending on isr.
                         */
-                       megasas_complete_cmd_dpc((unsigned long)instance);
+                       megasas_complete_cmd_dpc(&instance->isr_work);
                }
 
                msleep(1000);
@@ -4073,7 +4073,7 @@ megasas_deplete_reply_queue(struct megasas_instance 
*instance,
                }
        }
 
-       tasklet_schedule(&instance->isr_tasklet);
+       queue_work(system_bh_wq, &instance->isr_work);
        return IRQ_HANDLED;
 }
 
@@ -6313,8 +6313,7 @@ static int megasas_init_fw(struct megasas_instance 
*instance)
        dev_info(&instance->pdev->dev,
                "RDPQ mode\t: (%s)\n", instance->is_rdpq ? "enabled" : 
"disabled");
 
-       tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
-               (unsigned long)instance);
+       INIT_WORK(&instance->isr_work, instance->instancet->work);
 
        /*
         * Below are default value for legacy Firmware.
@@ -7757,7 +7756,7 @@ megasas_suspend(struct device *dev)
                instance->ev = NULL;
        }
 
-       tasklet_kill(&instance->isr_tasklet);
+       cancel_work_sync(&instance->isr_work);
 
        pci_set_drvdata(instance->pdev, instance);
        instance->instancet->disable_intr(instance);
@@ -7865,8 +7864,7 @@ megasas_resume(struct device *dev)
        if (megasas_get_ctrl_info(instance) != DCMD_SUCCESS)
                goto fail_init_mfi;
 
-       tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
-                    (unsigned long)instance);
+       INIT_WORK(&instance->isr_work, instance->instancet->work);
 
        if (instance->msix_vectors ?
                        megasas_setup_irqs_msix(instance, 0) :
@@ -7997,7 +7995,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
        /* cancel all wait events */
        wake_up_all(&instance->int_cmd_wait_q);
 
-       tasklet_kill(&instance->isr_tasklet);
+       cancel_work_sync(&instance->isr_work);
 
        /*
         * Take the instance off the instance array. Note that we will not
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c 
b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index c60014e07b44..7dd036b31a0c 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -3821,15 +3821,15 @@ int megasas_irqpoll(struct irq_poll *irqpoll, int 
budget)
 
 /**
  * megasas_complete_cmd_dpc_fusion -   Completes command
- * @instance_addr:                     Adapter soft state address
+ * @t:                                 pointer to the work_struct
  *
- * Tasklet to complete cmds
+ * Work to complete cmds
  */
 static void
-megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
+megasas_complete_cmd_dpc_fusion(struct work_struct *t)
 {
        struct megasas_instance *instance =
-               (struct megasas_instance *)instance_addr;
+               from_work(instance, t, isr_work);
        struct megasas_irq_context *irq_ctx = NULL;
        u32 count, MSIxIndex;
 
@@ -4180,7 +4180,7 @@ megasas_wait_for_outstanding_fusion(struct 
megasas_instance *instance,
        if (reason == MFI_IO_TIMEOUT_OCR) {
                dev_info(&instance->pdev->dev,
                        "MFI command is timed out\n");
-               megasas_complete_cmd_dpc_fusion((unsigned long)instance);
+               megasas_complete_cmd_dpc_fusion(&instance->isr_work);
                if (instance->snapdump_wait_time)
                        megasas_trigger_snap_dump(instance);
                retval = 1;
@@ -4196,7 +4196,7 @@ megasas_wait_for_outstanding_fusion(struct 
megasas_instance *instance,
                                   "FW in FAULT state Fault code:0x%x 
subcode:0x%x func:%s\n",
                                   abs_state & MFI_STATE_FAULT_CODE,
                                   abs_state & MFI_STATE_FAULT_SUBCODE, 
__func__);
-                       megasas_complete_cmd_dpc_fusion((unsigned 
long)instance);
+                       megasas_complete_cmd_dpc_fusion(&instance->isr_work);
                        if (instance->requestorId && reason) {
                                dev_warn(&instance->pdev->dev, "SR-IOV Found FW 
in FAULT"
                                " state while polling during"
@@ -4240,7 +4240,7 @@ megasas_wait_for_outstanding_fusion(struct 
megasas_instance *instance,
                        }
                }
 
-               megasas_complete_cmd_dpc_fusion((unsigned long)instance);
+               megasas_complete_cmd_dpc_fusion(&instance->isr_work);
                outstanding = atomic_read(&instance->fw_outstanding);
                if (!outstanding)
                        goto out;
@@ -5371,7 +5371,7 @@ struct megasas_instance_template 
megasas_instance_template_fusion = {
        .adp_reset = megasas_adp_reset_fusion,
        .check_reset = megasas_check_reset_fusion,
        .service_isr = megasas_isr_fusion,
-       .tasklet = megasas_complete_cmd_dpc_fusion,
+       .work = megasas_complete_cmd_dpc_fusion,
        .init_adapter = megasas_init_adapter_fusion,
        .build_and_issue_cmd = megasas_build_and_issue_cmd_fusion,
        .issue_dcmd = megasas_issue_dcmd_fusion,
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index 43ebb331e216..c8b3c18cfc6c 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -144,14 +144,14 @@ static void mvs_free(struct mvs_info *mvi)
        kfree(mvi);
 }
 
-#ifdef CONFIG_SCSI_MVSAS_TASKLET
-static void mvs_tasklet(unsigned long opaque)
+#ifdef CONFIG_SCSI_MVSAS_WORK
+static void mvs_work(struct work_struct *t)
 {
        u32 stat;
        u16 core_nr, i = 0;
 
-       struct mvs_info *mvi;
-       struct sas_ha_struct *sha = (struct sas_ha_struct *)opaque;
+       struct mvs_info *mvi = from_work(mvi, t, mv_work);
+       struct sas_ha_struct *sha = mvi->sha;
 
        core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
        mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
@@ -178,7 +178,7 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque)
        u32 stat;
        struct mvs_info *mvi;
        struct sas_ha_struct *sha = opaque;
-#ifndef CONFIG_SCSI_MVSAS_TASKLET
+#ifndef CONFIG_SCSI_MVSAS_WORK
        u32 i;
        u32 core_nr;
 
@@ -189,20 +189,20 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque)
 
        if (unlikely(!mvi))
                return IRQ_NONE;
-#ifdef CONFIG_SCSI_MVSAS_TASKLET
+#ifdef CONFIG_SCSI_MVSAS_WORK
        MVS_CHIP_DISP->interrupt_disable(mvi);
 #endif
 
        stat = MVS_CHIP_DISP->isr_status(mvi, irq);
        if (!stat) {
-       #ifdef CONFIG_SCSI_MVSAS_TASKLET
+       #ifdef CONFIG_SCSI_MVSAS_WORK
                MVS_CHIP_DISP->interrupt_enable(mvi);
        #endif
                return IRQ_NONE;
        }
 
-#ifdef CONFIG_SCSI_MVSAS_TASKLET
-       tasklet_schedule(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet);
+#ifdef CONFIG_SCSI_MVSAS_WORK
+       queue_work(system_bh_wq, &((struct mvs_prv_info 
*)sha->lldd_ha)->mv_work);
 #else
        for (i = 0; i < core_nr; i++) {
                mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
@@ -553,12 +553,11 @@ static int mvs_pci_init(struct pci_dev *pdev, const 
struct pci_device_id *ent)
                }
                nhost++;
        } while (nhost < chip->n_host);
-#ifdef CONFIG_SCSI_MVSAS_TASKLET
+#ifdef CONFIG_SCSI_MVSAS_WORK
        {
        struct mvs_prv_info *mpi = SHOST_TO_SAS_HA(shost)->lldd_ha;
 
-       tasklet_init(&(mpi->mv_tasklet), mvs_tasklet,
-                    (unsigned long)SHOST_TO_SAS_HA(shost));
+       INIT_WORK(&(mpi->mv_work), mvs_work);
        }
 #endif
 
@@ -603,8 +602,8 @@ static void mvs_pci_remove(struct pci_dev *pdev)
        core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
        mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
 
-#ifdef CONFIG_SCSI_MVSAS_TASKLET
-       tasklet_kill(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet);
+#ifdef CONFIG_SCSI_MVSAS_WORK
+       cancel_work_sync(&((struct mvs_prv_info *)sha->lldd_ha)->mv_work);
 #endif
 
        sas_unregister_ha(sha);
diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h
index 68df771e2975..2bf1af51e2a4 100644
--- a/drivers/scsi/mvsas/mv_sas.h
+++ b/drivers/scsi/mvsas/mv_sas.h
@@ -23,6 +23,7 @@
 #include <linux/irq.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/workqueue.h>
 #include <asm/unaligned.h>
 #include <scsi/libsas.h>
 #include <scsi/scsi.h>
@@ -402,7 +403,7 @@ struct mvs_prv_info{
        u8 scan_finished;
        u8 reserve;
        struct mvs_info *mvi[2];
-       struct tasklet_struct mv_tasklet;
+       struct work_struct mv_work;
 };
 
 struct mvs_wq {
@@ -432,8 +433,8 @@ void mvs_set_sas_addr(struct mvs_info *mvi, int port_id, 
u32 off_lo,
                      u32 off_hi, u64 sas_addr);
 void mvs_scan_start(struct Scsi_Host *shost);
 int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time);
-int mvs_queue_command(struct sas_task *task, gfp_t gfp_flags);
-int mvs_abort_task(struct sas_task *task);
+int mvs_queue_command(struct sas_task *work, gfp_t gfp_flags);
+int mvs_abort_task(struct sas_task *work);
 void mvs_port_formed(struct asd_sas_phy *sas_phy);
 void mvs_port_deformed(struct asd_sas_phy *sas_phy);
 int mvs_dev_found(struct domain_device *dev);
@@ -441,7 +442,7 @@ void mvs_dev_gone(struct domain_device *dev);
 int mvs_lu_reset(struct domain_device *dev, u8 *lun);
 int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags);
 int mvs_I_T_nexus_reset(struct domain_device *dev);
-int mvs_query_task(struct sas_task *task);
+int mvs_query_task(struct sas_task *work);
 void mvs_release_task(struct mvs_info *mvi,
                        struct domain_device *dev);
 void mvs_do_release_task(struct mvs_info *mvi, int phy_no,
diff --git a/drivers/scsi/pm8001/pm8001_init.c 
b/drivers/scsi/pm8001/pm8001_init.c
index ed6b7d954dda..bda175682785 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -60,8 +60,8 @@ bool pm8001_use_msix = true;
 module_param_named(use_msix, pm8001_use_msix, bool, 0444);
 MODULE_PARM_DESC(zoned, "Use MSIX interrupts. Default: true");
 
-static bool pm8001_use_tasklet = true;
-module_param_named(use_tasklet, pm8001_use_tasklet, bool, 0444);
+static bool pm8001_use_bh_work = true;
+module_param_named(use_bh_work, pm8001_use_bh_work, bool, 0444);
 MODULE_PARM_DESC(zoned, "Use MSIX interrupts. Default: true");
 
 static bool pm8001_read_wwn = true;
@@ -213,14 +213,17 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha)
 }
 
 /**
- * pm8001_tasklet() - tasklet for 64 msi-x interrupt handler
- * @opaque: the passed general host adapter struct
- * Note: pm8001_tasklet is common for pm8001 & pm80xx
+ * pm8001_work() - BH work for 64 msi-x interrupt handler
+ * @t: pointer to work_struct
+ * Note: pm8001_work is common for pm8001 & pm80xx
  */
-static void pm8001_tasklet(unsigned long opaque)
+static void pm8001_work(struct work_struct *t)
 {
-       struct isr_param *irq_vector = (struct isr_param *)opaque;
-       struct pm8001_hba_info *pm8001_ha = irq_vector->drv_inst;
+       /*FIXME: Since we don't know the index, we need a
+        * mechanism to determine it or always use index 0
+        */
+       struct pm8001_hba_info *pm8001_ha = from_work(pm8001_ha, t, work[0]);
+       struct isr_param *irq_vector = pm8001_ha->irq_vector;
 
        if (WARN_ON_ONCE(!pm8001_ha))
                return;
@@ -228,41 +231,39 @@ static void pm8001_tasklet(unsigned long opaque)
        PM8001_CHIP_DISP->isr(pm8001_ha, irq_vector->irq_id);
 }
 
-static void pm8001_init_tasklet(struct pm8001_hba_info *pm8001_ha)
+static void pm8001_init_work(struct pm8001_hba_info *pm8001_ha)
 {
        int i;
 
-       if (!pm8001_use_tasklet)
+       if (!pm8001_use_bh_work)
                return;
 
-       /*  Tasklet for non msi-x interrupt handler */
+       /*  Work for non msi-x interrupt handler */
        if ((!pm8001_ha->pdev->msix_cap || !pci_msi_enabled()) ||
            (pm8001_ha->chip_id == chip_8001)) {
-               tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet,
-                            (unsigned long)&(pm8001_ha->irq_vector[0]));
+               INIT_WORK(&pm8001_ha->work[0], pm8001_work);
                return;
        }
        for (i = 0; i < PM8001_MAX_MSIX_VEC; i++)
-               tasklet_init(&pm8001_ha->tasklet[i], pm8001_tasklet,
-                            (unsigned long)&(pm8001_ha->irq_vector[i]));
+               INIT_WORK(&pm8001_ha->work[i], pm8001_work);
 }
 
-static void pm8001_kill_tasklet(struct pm8001_hba_info *pm8001_ha)
+static void pm8001_cancel_work(struct pm8001_hba_info *pm8001_ha)
 {
        int i;
 
-       if (!pm8001_use_tasklet)
+       if (!pm8001_use_bh_work)
                return;
 
        /* For non-msix and msix interrupts */
        if ((!pm8001_ha->pdev->msix_cap || !pci_msi_enabled()) ||
            (pm8001_ha->chip_id == chip_8001)) {
-               tasklet_kill(&pm8001_ha->tasklet[0]);
+               cancel_work_sync(&pm8001_ha->work[0]);
                return;
        }
 
        for (i = 0; i < PM8001_MAX_MSIX_VEC; i++)
-               tasklet_kill(&pm8001_ha->tasklet[i]);
+               cancel_work_sync(&pm8001_ha->work[i]);
 }
 
 static irqreturn_t pm8001_handle_irq(struct pm8001_hba_info *pm8001_ha,
@@ -274,10 +275,10 @@ static irqreturn_t pm8001_handle_irq(struct 
pm8001_hba_info *pm8001_ha,
        if (!PM8001_CHIP_DISP->is_our_interrupt(pm8001_ha))
                return IRQ_NONE;
 
-       if (!pm8001_use_tasklet)
+       if (!pm8001_use_bh_work)
                return PM8001_CHIP_DISP->isr(pm8001_ha, irq);
 
-       tasklet_schedule(&pm8001_ha->tasklet[irq]);
+       queue_work(system_bh_wq, &pm8001_ha->work[irq]);
        return IRQ_HANDLED;
 }
 
@@ -580,7 +581,7 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct 
pci_dev *pdev,
        else
                pm8001_ha->iomb_size = IOMB_SIZE_SPC;
 
-       pm8001_init_tasklet(pm8001_ha);
+       pm8001_init_work(pm8001_ha);
 
        if (pm8001_ioremap(pm8001_ha))
                goto failed_pci_alloc;
@@ -1318,7 +1319,7 @@ static void pm8001_pci_remove(struct pci_dev *pdev)
        PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha);
 
        pm8001_free_irq(pm8001_ha);
-       pm8001_kill_tasklet(pm8001_ha);
+       pm8001_cancel_work(pm8001_ha);
        scsi_host_put(pm8001_ha->shost);
 
        for (i = 0; i < pm8001_ha->ccb_count; i++) {
@@ -1361,7 +1362,7 @@ static int __maybe_unused pm8001_pci_suspend(struct 
device *dev)
        PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha);
 
        pm8001_free_irq(pm8001_ha);
-       pm8001_kill_tasklet(pm8001_ha);
+       pm8001_cancel_work(pm8001_ha);
 
        pm8001_info(pm8001_ha, "pdev=0x%p, slot=%s, entering "
                      "suspended state\n", pdev,
@@ -1410,7 +1411,7 @@ static int __maybe_unused pm8001_pci_resume(struct device 
*dev)
        if (rc)
                goto err_out_disable;
 
-       pm8001_init_tasklet(pm8001_ha);
+       pm8001_init_work(pm8001_ha);
 
        PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, 0);
        if (pm8001_ha->chip_id != chip_8001) {
@@ -1543,8 +1544,8 @@ static int __init pm8001_init(void)
 {
        int rc = -ENOMEM;
 
-       if (pm8001_use_tasklet && !pm8001_use_msix)
-               pm8001_use_tasklet = false;
+       if (pm8001_use_bh_work && !pm8001_use_msix)
+               pm8001_use_bh_work = false;
 
        pm8001_wq = alloc_workqueue("pm80xx", 0, 0);
        if (!pm8001_wq)
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 3ccb7371902f..08ab597406c7 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -522,7 +522,7 @@ struct pm8001_hba_info {
        int                     number_of_intr;/*will be used in remove()*/
        char                    intr_drvname[PM8001_MAX_MSIX_VEC]
                                [PM8001_NAME_LENGTH+1+3+1];
-       struct tasklet_struct   tasklet[PM8001_MAX_MSIX_VEC];
+       struct work_struct      work[PM8001_MAX_MSIX_VEC];
        u32                     logging_level;
        u32                     link_rate;
        u32                     fw_status;
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index e8bcc3a88732..be21c0ffe002 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -859,7 +859,7 @@ static void _pmcraid_fire_command(struct pmcraid_cmd *cmd)
        /* Add this command block to pending cmd pool. We do this prior to
         * writting IOARCB to ioarrin because IOA might complete the command
         * by the time we are about to add it to the list. Response handler
-        * (isr/tasklet) looks for cmd block in the pending pending list.
+        * (isr/BH work) looks for cmd block in the pending list.
         */
        spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags);
        list_add_tail(&cmd->free_list, &pinstance->pending_cmd_pool);
@@ -1077,7 +1077,7 @@ static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd)
 
        /* Subsequent commands require HRRQ identification to be successful.
         * Note that this gets called even during reset from SCSI mid-layer
-        * or tasklet
+        * or BH work
         */
        pmcraid_send_cmd(cmd, done_function,
                         PMCRAID_INTERNAL_TIMEOUT,
@@ -1843,7 +1843,7 @@ static void pmcraid_unregister_hcams(struct pmcraid_cmd 
*cmd)
 {
        struct pmcraid_instance *pinstance = cmd->drv_inst;
 
-       /* During IOA bringdown, HCAM gets fired and tasklet proceeds with
+       /* During IOA bringdown, HCAM gets fired and BH work proceeds with
         * handling hcam response though it is not necessary. In order to
         * prevent this, set 'ignore', so that bring-down sequence doesn't
         * re-send any more hcams
@@ -1916,7 +1916,7 @@ static void pmcraid_soft_reset(struct pmcraid_cmd *cmd)
        u32 doorbell;
 
        /* There will be an interrupt when Transition to Operational bit is
-        * set so tasklet would execute next reset task. The timeout handler
+        * set so BH work would execute next reset task. The timeout handler
         * would re-initiate a reset
         */
        cmd->cmd_done = pmcraid_ioa_reset;
@@ -2039,7 +2039,7 @@ static void pmcraid_fail_outstanding_cmds(struct 
pmcraid_instance *pinstance)
  * @cmd: pointer to the cmd block to be used for entire reset process
  *
  * This function executes most of the steps required for IOA reset. This gets
- * called by user threads (modprobe/insmod/rmmod) timer, tasklet and midlayer's
+ * called by user threads (modprobe/insmod/rmmod) timer, BH work and midlayer's
  * 'eh_' thread. Access to variables used for controlling the reset sequence is
  * synchronized using host lock. Various functions called during reset process
  * would make use of a single command block, pointer to which is also stored in
@@ -2199,7 +2199,7 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd)
                pinstance->ioa_state = IOA_STATE_IN_BRINGUP;
 
                /* Initialization commands start with HRRQ identification. From
-                * now on tasklet completes most of the commands as IOA is up
+                * now on BH work completes most of the commands as IOA is up
                 * and intrs are enabled
                 */
                pmcraid_identify_hrrq(cmd);
@@ -2261,7 +2261,7 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd)
 
 /**
  * pmcraid_initiate_reset - initiates reset sequence. This is called from
- * ISR/tasklet during error interrupts including IOA unit check. If reset
+ * ISR/BH work during error interrupts including IOA unit check. If reset
  * is already in progress, it just returns, otherwise initiates IOA reset
  * to bring IOA up to operational state.
  *
@@ -2303,7 +2303,7 @@ static void pmcraid_initiate_reset(struct 
pmcraid_instance *pinstance)
  * @target_state: expected target state after reset
  *
  * Note: This command initiates reset and waits for its completion. Hence this
- * should not be called from isr/timer/tasklet functions (timeout handlers,
+ * should not be called from isr/timer/BH work functions (timeout handlers,
  * error response handlers and interrupt handlers).
  *
  * Return Value
@@ -2449,7 +2449,7 @@ static void pmcraid_request_sense(struct pmcraid_cmd *cmd)
        ioadl->flags = IOADL_FLAGS_LAST_DESC;
 
        /* request sense might be called as part of error response processing
-        * which runs in tasklets context. It is possible that mid-layer might
+        * which runs in works context. It is possible that mid-layer might
         * schedule queuecommand during this time, hence, writting to IOARRIN
         * must be protect by host_lock
         */
@@ -2566,7 +2566,7 @@ static void pmcraid_frame_auto_sense(struct pmcraid_cmd 
*cmd)
  * @cmd: pointer to pmcraid_cmd that has failed
  *
  * This function determines whether or not to initiate ERP on the affected
- * device. This is called from a tasklet, which doesn't hold any locks.
+ * device. This is called from a BH work, which doesn't hold any locks.
  *
  * Return value:
  *      0 it caller can complete the request, otherwise 1 where in error
@@ -2825,7 +2825,7 @@ static int _pmcraid_io_done(struct pmcraid_cmd *cmd, int 
reslen, int ioasc)
  *
  * @cmd: pointer to pmcraid command struct
  *
- * This function is invoked by tasklet/mid-layer error handler to completing
+ * This function is invoked by BH work/mid-layer error handler to completing
  * the SCSI ops sent from mid-layer.
  *
  * Return value
@@ -3743,7 +3743,7 @@ static irqreturn_t pmcraid_isr_msix(int irq, void *dev_id)
                }
        }
 
-       tasklet_schedule(&(pinstance->isr_tasklet[hrrq_id]));
+       queue_work(system_bh_wq, &(pinstance->isr_work[hrrq_id]));
 
        return IRQ_HANDLED;
 }
@@ -3811,8 +3811,8 @@ static irqreturn_t pmcraid_isr(int irq, void *dev_id)
                        ioread32(
                                pinstance->int_regs.ioa_host_interrupt_clr_reg);
 
-                       tasklet_schedule(
-                                       &(pinstance->isr_tasklet[hrrq_id]));
+                       queue_work(system_bh_wq,
+                                       &(pinstance->isr_work[hrrq_id]));
                }
        }
 
@@ -3918,14 +3918,14 @@ static void pmcraid_worker_function(struct work_struct 
*workp)
 }
 
 /**
- * pmcraid_tasklet_function - Tasklet function
+ * pmcraid_work_function - Work function
  *
- * @instance: pointer to msix param structure
+ * @t:  pointer to work_struct
  *
  * Return Value
  *     None
  */
-static void pmcraid_tasklet_function(unsigned long instance)
+static void pmcraid_work_function(struct work_struct *t)
 {
        struct pmcraid_isr_param *hrrq_vector;
        struct pmcraid_instance *pinstance;
@@ -3936,14 +3936,17 @@ static void pmcraid_tasklet_function(unsigned long 
instance)
        int id;
        u32 resp;
 
-       hrrq_vector = (struct pmcraid_isr_param *)instance;
-       pinstance = hrrq_vector->drv_inst;
+       /* FIXME: Since we don't know the index, we need a
+        * mechanism to determine it or always use index 0
+        */
+       pinstance = from_work(pinstance, t, isr_work[0]);
+       hrrq_vector = pinstance->hrrq_vector;
        id = hrrq_vector->hrrq_id;
        lockp = &(pinstance->hrrq_lock[id]);
 
        /* loop through each of the commands responded by IOA. Each HRRQ buf is
         * protected by its own lock. Traversals must be done within this lock
-        * as there may be multiple tasklets running on multiple CPUs. Note
+        * as there may be multiple works running on multiple CPUs. Note
         * that the lock is held just for picking up the response handle and
         * manipulating hrrq_curr/toggle_bit values.
         */
@@ -4416,35 +4419,34 @@ static int pmcraid_allocate_config_buffers(struct 
pmcraid_instance *pinstance)
 }
 
 /**
- * pmcraid_init_tasklets - registers tasklets for response handling
+ * pmcraid_init_works - registers works for response handling
  *
  * @pinstance: pointer adapter instance structure
  *
  * Return value
  *     none
  */
-static void pmcraid_init_tasklets(struct pmcraid_instance *pinstance)
+static void pmcraid_init_works(struct pmcraid_instance *pinstance)
 {
        int i;
        for (i = 0; i < pinstance->num_hrrq; i++)
-               tasklet_init(&pinstance->isr_tasklet[i],
-                            pmcraid_tasklet_function,
-                            (unsigned long)&pinstance->hrrq_vector[i]);
+               INIT_WORK(&pinstance->isr_work[i],
+                            pmcraid_work_function);
 }
 
 /**
- * pmcraid_kill_tasklets - destroys tasklets registered for response handling
+ * pmcraid_kill_works - destroys works registered for response handling
  *
  * @pinstance: pointer to adapter instance structure
  *
  * Return value
  *     none
  */
-static void pmcraid_kill_tasklets(struct pmcraid_instance *pinstance)
+static void pmcraid_kill_works(struct pmcraid_instance *pinstance)
 {
        int i;
        for (i = 0; i < pinstance->num_hrrq; i++)
-               tasklet_kill(&pinstance->isr_tasklet[i]);
+               cancel_work_sync(&pinstance->isr_work[i]);
 }
 
 /**
@@ -4770,7 +4772,7 @@ static void pmcraid_remove(struct pci_dev *pdev)
        pmcraid_disable_interrupts(pinstance, ~0);
        flush_work(&pinstance->worker_q);
 
-       pmcraid_kill_tasklets(pinstance);
+       pmcraid_kill_works(pinstance);
        pmcraid_unregister_interrupt_handler(pinstance);
        pmcraid_release_buffers(pinstance);
        iounmap(pinstance->mapped_dma_addr);
@@ -4794,7 +4796,7 @@ static int __maybe_unused pmcraid_suspend(struct device 
*dev)
 
        pmcraid_shutdown(pdev);
        pmcraid_disable_interrupts(pinstance, ~0);
-       pmcraid_kill_tasklets(pinstance);
+       pmcraid_kill_works(pinstance);
        pmcraid_unregister_interrupt_handler(pinstance);
 
        return 0;
@@ -4836,7 +4838,7 @@ static int __maybe_unused pmcraid_resume(struct device 
*dev)
                goto release_host;
        }
 
-       pmcraid_init_tasklets(pinstance);
+       pmcraid_init_works(pinstance);
        pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS);
 
        /* Start with hard reset sequence which brings up IOA to operational
@@ -4850,14 +4852,14 @@ static int __maybe_unused pmcraid_resume(struct device 
*dev)
        if (pmcraid_reset_bringup(pinstance)) {
                dev_err(&pdev->dev, "couldn't initialize IOA\n");
                rc = -ENODEV;
-               goto release_tasklets;
+               goto release_works;
        }
 
        return 0;
 
-release_tasklets:
+release_works:
        pmcraid_disable_interrupts(pinstance, ~0);
-       pmcraid_kill_tasklets(pinstance);
+       pmcraid_kill_works(pinstance);
        pmcraid_unregister_interrupt_handler(pinstance);
 
 release_host:
@@ -4869,7 +4871,7 @@ static int __maybe_unused pmcraid_resume(struct device 
*dev)
 }
 
 /**
- * pmcraid_complete_ioa_reset - Called by either timer or tasklet during
+ * pmcraid_complete_ioa_reset - Called by either timer or BH work during
  *                             completion of the ioa reset
  * @cmd: pointer to reset command block
  */
@@ -5014,7 +5016,7 @@ static void pmcraid_init_res_table(struct pmcraid_cmd 
*cmd)
 
        /* resource list is protected by pinstance->resource_lock.
         * init_res_table can be called from probe (user-thread) or runtime
-        * reset (timer/tasklet)
+        * reset (timer/BH work)
         */
        spin_lock_irqsave(&pinstance->resource_lock, lock_flags);
 
@@ -5281,7 +5283,7 @@ static int pmcraid_probe(struct pci_dev *pdev,
                goto out_scsi_host_put;
        }
 
-       pmcraid_init_tasklets(pinstance);
+       pmcraid_init_works(pinstance);
 
        /* allocate verious buffers used by LLD.*/
        rc = pmcraid_init_buffers(pinstance);
@@ -5337,7 +5339,7 @@ static int pmcraid_probe(struct pci_dev *pdev,
        pmcraid_release_buffers(pinstance);
 
 out_unregister_isr:
-       pmcraid_kill_tasklets(pinstance);
+       pmcraid_kill_works(pinstance);
        pmcraid_unregister_interrupt_handler(pinstance);
 
 out_scsi_host_put:
diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h
index 9f59930e8b4f..2c17b1f4b57e 100644
--- a/drivers/scsi/pmcraid.h
+++ b/drivers/scsi/pmcraid.h
@@ -20,6 +20,7 @@
 #include <net/netlink.h>
 #include <net/genetlink.h>
 #include <linux/connector.h>
+#include <linux/workqueue.h>
 /*
  * Driver name   : string representing the driver name
  * Device file   : /dev file to be used for management interfaces
@@ -752,8 +753,8 @@ struct pmcraid_instance {
        spinlock_t free_pool_lock;              /* free pool lock */
        spinlock_t pending_pool_lock;           /* pending pool lock */
 
-       /* Tasklet to handle deferred processing */
-       struct tasklet_struct isr_tasklet[PMCRAID_NUM_MSIX_VECTORS];
+       /* BH work to handle deferred processing */
+       struct work_struct isr_work[PMCRAID_NUM_MSIX_VECTORS];
 
        /* Work-queue (Shared) for deferred reset processing */
        struct work_struct worker_q;
-- 
2.17.1

Reply via email to