Patchwork [v8,13/13] libsas: trim sas_task of slow path infrastructure

login
register
mail settings
Submitter Dan Williams
Date Feb. 10, 2012, 8:45 a.m.
Message ID <20120210084545.25701.4897.stgit@dwillia2-linux.jf.intel.com>
Download mbox | patch
Permalink /patch/140535/
State Not Applicable
Delegated to: David Miller
Headers show

Comments

Dan Williams - Feb. 10, 2012, 8:45 a.m.
The timer and the completion are only used for slow path tasks (smp, and
lldd tmfs), yet we incur the allocation space and cpu setup time for
every fast path task.

Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/libsas/sas_expander.c  |   20 ++++++++++----------
 drivers/scsi/libsas/sas_init.c      |   23 +++++++++++++++++++++--
 drivers/scsi/libsas/sas_scsi_host.c |    8 ++++++--
 drivers/scsi/mvsas/mv_sas.c         |   20 ++++++++++----------
 drivers/scsi/pm8001/pm8001_sas.c    |   30 +++++++++++++++---------------
 include/scsi/libsas.h               |   14 +++++++++-----
 6 files changed, 71 insertions(+), 44 deletions(-)


--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jack Wang - Feb. 15, 2012, 1:09 a.m.
Dear Dan,

You seems forget change sas_alloc_task to sas_alloc_slow_task in pm8001.
I'll post a patch to fix this later.
Thanks for your work.

Jack
[PATCH v8 13/13] libsas: trim sas_task of slow path infrastructure
> 
> The timer and the completion are only used for slow path tasks (smp, and
> lldd tmfs), yet we incur the allocation space and cpu setup time for
> every fast path task.
> 
> Cc: Christoph Hellwig <hch@lst.de>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---
>  drivers/scsi/libsas/sas_expander.c  |   20 ++++++++++----------
>  drivers/scsi/libsas/sas_init.c      |   23 +++++++++++++++++++++--
>  drivers/scsi/libsas/sas_scsi_host.c |    8 ++++++--
>  drivers/scsi/mvsas/mv_sas.c         |   20 ++++++++++----------
>  drivers/scsi/pm8001/pm8001_sas.c    |   30 +++++++++++++++---------------
>  include/scsi/libsas.h               |   14 +++++++++-----
>  6 files changed, 71 insertions(+), 44 deletions(-)
> 
> diff --git a/drivers/scsi/libsas/sas_expander.c
> b/drivers/scsi/libsas/sas_expander.c
> index 05acd9e..0ab3796 100644
> --- a/drivers/scsi/libsas/sas_expander.c
> +++ b/drivers/scsi/libsas/sas_expander.c
> @@ -51,14 +51,14 @@ static void smp_task_timedout(unsigned long _task)
>  		task->task_state_flags |= SAS_TASK_STATE_ABORTED;
>  	spin_unlock_irqrestore(&task->task_state_lock, flags);
> 
> -	complete(&task->completion);
> +	complete(&task->slow_task->completion);
>  }
> 
>  static void smp_task_done(struct sas_task *task)
>  {
> -	if (!del_timer(&task->timer))
> +	if (!del_timer(&task->slow_task->timer))
>  		return;
> -	complete(&task->completion);
> +	complete(&task->slow_task->completion);
>  }
> 
>  /* Give it some long enough timeout. In seconds. */
> @@ -79,7 +79,7 @@ static int smp_execute_task(struct domain_device *dev,
void
> *req, int req_size,
>  			break;
>  		}
> 
> -		task = sas_alloc_task(GFP_KERNEL);
> +		task = sas_alloc_slow_task(GFP_KERNEL);
>  		if (!task) {
>  			res = -ENOMEM;
>  			break;
> @@ -91,20 +91,20 @@ static int smp_execute_task(struct domain_device *dev,
> void *req, int req_size,
> 
>  		task->task_done = smp_task_done;
> 
> -		task->timer.data = (unsigned long) task;
> -		task->timer.function = smp_task_timedout;
> -		task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
> -		add_timer(&task->timer);
> +		task->slow_task->timer.data = (unsigned long) task;
> +		task->slow_task->timer.function = smp_task_timedout;
> +		task->slow_task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
> +		add_timer(&task->slow_task->timer);
> 
>  		res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
> 
>  		if (res) {
> -			del_timer(&task->timer);
> +			del_timer(&task->slow_task->timer);
>  			SAS_DPRINTK("executing SMP task failed:%d\n", res);
>  			break;
>  		}
> 
> -		wait_for_completion(&task->completion);
> +		wait_for_completion(&task->slow_task->completion);
>  		res = -ECOMM;
>  		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
>  			SAS_DPRINTK("smp task timed out or aborted\n");
> diff --git a/drivers/scsi/libsas/sas_init.c
> b/drivers/scsi/libsas/sas_init.c
> index 2fc23d3..57e7ac9 100644
> --- a/drivers/scsi/libsas/sas_init.c
> +++ b/drivers/scsi/libsas/sas_init.c
> @@ -48,18 +48,37 @@ struct sas_task *sas_alloc_task(gfp_t flags)
>  		INIT_LIST_HEAD(&task->list);
>  		spin_lock_init(&task->task_state_lock);
>  		task->task_state_flags = SAS_TASK_STATE_PENDING;
> -		init_timer(&task->timer);
> -		init_completion(&task->completion);
>  	}
> 
>  	return task;
>  }
>  EXPORT_SYMBOL_GPL(sas_alloc_task);
> 
> +struct sas_task *sas_alloc_slow_task(gfp_t flags)
> +{
> +	struct sas_task *task = sas_alloc_task(flags);
> +	struct sas_task_slow *slow = kmalloc(sizeof(*slow), flags);
> +
> +	if (!task || !slow) {
> +		if (task)
> +			kmem_cache_free(sas_task_cache, task);
> +		kfree(slow);
> +		return NULL;
> +	}
> +
> +	task->slow_task = slow;
> +	init_timer(&slow->timer);
> +	init_completion(&slow->completion);
> +
> +	return task;
> +}
> +EXPORT_SYMBOL_GPL(sas_alloc_slow_task);
> +
>  void sas_free_task(struct sas_task *task)
>  {
>  	if (task) {
>  		BUG_ON(!list_empty(&task->list));
> +		kfree(task->slow_task);
>  		kmem_cache_free(sas_task_cache, task);
>  	}
>  }
> diff --git a/drivers/scsi/libsas/sas_scsi_host.c
> b/drivers/scsi/libsas/sas_scsi_host.c
> index 86ffd8f..9716f2e 100644
> --- a/drivers/scsi/libsas/sas_scsi_host.c
> +++ b/drivers/scsi/libsas/sas_scsi_host.c
> @@ -1013,9 +1013,13 @@ void sas_task_abort(struct sas_task *task)
> 
>  	/* Escape for libsas internal commands */
>  	if (!sc) {
> -		if (!del_timer(&task->timer))
> +		struct sas_task_slow *slow = task->slow_task;
> +
> +		if (!slow)
> +			return;
> +		if (!del_timer(&slow->timer))
>  			return;
> -		task->timer.function(task->timer.data);
> +		slow->timer.function(slow->timer.data);
>  		return;
>  	}
> 
> diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
> index b68a653..d0462b8 100644
> --- a/drivers/scsi/mvsas/mv_sas.c
> +++ b/drivers/scsi/mvsas/mv_sas.c
> @@ -1365,9 +1365,9 @@ void mvs_dev_gone(struct domain_device *dev)
> 
>  static void mvs_task_done(struct sas_task *task)
>  {
> -	if (!del_timer(&task->timer))
> +	if (!del_timer(&task->slow_task->timer))
>  		return;
> -	complete(&task->completion);
> +	complete(&task->slow_task->completion);
>  }
> 
>  static void mvs_tmf_timedout(unsigned long data)
> @@ -1375,7 +1375,7 @@ static void mvs_tmf_timedout(unsigned long data)
>  	struct sas_task *task = (struct sas_task *)data;
> 
>  	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
> -	complete(&task->completion);
> +	complete(&task->slow_task->completion);
>  }
> 
>  #define MVS_TASK_TIMEOUT 20
> @@ -1386,7 +1386,7 @@ static int mvs_exec_internal_tmf_task(struct
> domain_device *dev,
>  	struct sas_task *task = NULL;
> 
>  	for (retry = 0; retry < 3; retry++) {
> -		task = sas_alloc_task(GFP_KERNEL);
> +		task = sas_alloc_slow_task(GFP_KERNEL);
>  		if (!task)
>  			return -ENOMEM;
> 
> @@ -1396,20 +1396,20 @@ static int mvs_exec_internal_tmf_task(struct
> domain_device *dev,
>  		memcpy(&task->ssp_task, parameter, para_len);
>  		task->task_done = mvs_task_done;
> 
> -		task->timer.data = (unsigned long) task;
> -		task->timer.function = mvs_tmf_timedout;
> -		task->timer.expires = jiffies + MVS_TASK_TIMEOUT*HZ;
> -		add_timer(&task->timer);
> +		task->slow_task->timer.data = (unsigned long) task;
> +		task->slow_task->timer.function = mvs_tmf_timedout;
> +		task->slow_task->timer.expires = jiffies +
MVS_TASK_TIMEOUT*HZ;
> +		add_timer(&task->slow_task->timer);
> 
>  		res = mvs_task_exec(task, 1, GFP_KERNEL, NULL, 1, tmf);
> 
>  		if (res) {
> -			del_timer(&task->timer);
> +			del_timer(&task->slow_task->timer);
>  			mv_printk("executing internel task failed:%d\n",
res);
>  			goto ex_err;
>  		}
> 
> -		wait_for_completion(&task->completion);
> +		wait_for_completion(&task->slow_task->completion);
>  		res = TMF_RESP_FUNC_FAILED;
>  		/* Even TMF timed out, return direct. */
>  		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
> diff --git a/drivers/scsi/pm8001/pm8001_sas.c
> b/drivers/scsi/pm8001/pm8001_sas.c
> index b111018..ad36f1a 100644
> --- a/drivers/scsi/pm8001/pm8001_sas.c
> +++ b/drivers/scsi/pm8001/pm8001_sas.c
> @@ -627,9 +627,9 @@ int pm8001_dev_found(struct domain_device *dev)
> 
>  static void pm8001_task_done(struct sas_task *task)
>  {
> -	if (!del_timer(&task->timer))
> +	if (!del_timer(&task->slow_task->timer))
>  		return;
> -	complete(&task->completion);
> +	complete(&task->slow_task->completion);
>  }
> 
>  static void pm8001_tmf_timedout(unsigned long data)
> @@ -637,7 +637,7 @@ static void pm8001_tmf_timedout(unsigned long data)
>  	struct sas_task *task = (struct sas_task *)data;
> 
>  	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
> -	complete(&task->completion);
> +	complete(&task->slow_task->completion);
>  }
> 
>  #define PM8001_TASK_TIMEOUT 20
> @@ -668,21 +668,21 @@ static int pm8001_exec_internal_tmf_task(struct
> domain_device *dev,
>  		task->task_proto = dev->tproto;
>  		memcpy(&task->ssp_task, parameter, para_len);
>  		task->task_done = pm8001_task_done;
> -		task->timer.data = (unsigned long)task;
> -		task->timer.function = pm8001_tmf_timedout;
> -		task->timer.expires = jiffies + PM8001_TASK_TIMEOUT*HZ;
> -		add_timer(&task->timer);
> +		task->slow_task->timer.data = (unsigned long)task;
> +		task->slow_task->timer.function = pm8001_tmf_timedout;
> +		task->slow_task->timer.expires = jiffies +
PM8001_TASK_TIMEOUT*HZ;
> +		add_timer(&task->slow_task->timer);
> 
>  		res = pm8001_task_exec(task, 1, GFP_KERNEL, 1, tmf);
> 
>  		if (res) {
> -			del_timer(&task->timer);
> +			del_timer(&task->slow_task->timer);
>  			PM8001_FAIL_DBG(pm8001_ha,
>  				pm8001_printk("Executing internal task "
>  				"failed\n"));
>  			goto ex_err;
>  		}
> -		wait_for_completion(&task->completion);
> +		wait_for_completion(&task->slow_task->completion);
>  		res = -TMF_RESP_FUNC_FAILED;
>  		/* Even TMF timed out, return direct. */
>  		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
> @@ -749,10 +749,10 @@ pm8001_exec_internal_task_abort(struct
pm8001_hba_info
> *pm8001_ha,
>  		task->dev = dev;
>  		task->task_proto = dev->tproto;
>  		task->task_done = pm8001_task_done;
> -		task->timer.data = (unsigned long)task;
> -		task->timer.function = pm8001_tmf_timedout;
> -		task->timer.expires = jiffies + PM8001_TASK_TIMEOUT * HZ;
> -		add_timer(&task->timer);
> +		task->slow_task->timer.data = (unsigned long)task;
> +		task->slow_task->timer.function = pm8001_tmf_timedout;
> +		task->slow_task->timer.expires = jiffies +
PM8001_TASK_TIMEOUT *
> HZ;
> +		add_timer(&task->slow_task->timer);
> 
>  		res = pm8001_tag_alloc(pm8001_ha, &ccb_tag);
>  		if (res)
> @@ -766,13 +766,13 @@ pm8001_exec_internal_task_abort(struct
pm8001_hba_info
> *pm8001_ha,
>  			pm8001_dev, flag, task_tag, ccb_tag);
> 
>  		if (res) {
> -			del_timer(&task->timer);
> +			del_timer(&task->slow_task->timer);
>  			PM8001_FAIL_DBG(pm8001_ha,
>  				pm8001_printk("Executing internal task "
>  				"failed\n"));
>  			goto ex_err;
>  		}
> -		wait_for_completion(&task->completion);
> +		wait_for_completion(&task->slow_task->completion);
>  		res = TMF_RESP_FUNC_FAILED;
>  		/* Even TMF timed out, return direct. */
>  		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
> diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
> index 484bc52..4e84ef3 100644
> --- a/include/scsi/libsas.h
> +++ b/include/scsi/libsas.h
> @@ -568,10 +568,6 @@ struct sas_task {
> 
>  	enum   sas_protocol      task_proto;
> 
> -	/* Used by the discovery code. */
> -	struct timer_list     timer;
> -	struct completion     completion;
> -
>  	union {
>  		struct sas_ata_task ata_task;
>  		struct sas_smp_task smp_task;
> @@ -588,8 +584,15 @@ struct sas_task {
> 
>  	void   *lldd_task;	  /* for use by LLDDs */
>  	void   *uldd_task;
> +	struct sas_task_slow *slow_task;
> +};
> 
> -	struct work_struct abort_work;
> +struct sas_task_slow {
> +	/* standard/extra infrastructure for slow path commands (SMP and
> +	 * internal lldd commands
> +	 */
> +	struct timer_list     timer;
> +	struct completion     completion;
>  };
> 
>  #define SAS_TASK_STATE_PENDING      1
> @@ -599,6 +602,7 @@ struct sas_task {
>  #define SAS_TASK_AT_INITIATOR       16
> 
>  extern struct sas_task *sas_alloc_task(gfp_t flags);
> +extern struct sas_task *sas_alloc_slow_task(gfp_t flags);
>  extern void sas_free_task(struct sas_task *task);
> 
>  struct sas_domain_function_template {
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 05acd9e..0ab3796 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -51,14 +51,14 @@  static void smp_task_timedout(unsigned long _task)
 		task->task_state_flags |= SAS_TASK_STATE_ABORTED;
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
 
-	complete(&task->completion);
+	complete(&task->slow_task->completion);
 }
 
 static void smp_task_done(struct sas_task *task)
 {
-	if (!del_timer(&task->timer))
+	if (!del_timer(&task->slow_task->timer))
 		return;
-	complete(&task->completion);
+	complete(&task->slow_task->completion);
 }
 
 /* Give it some long enough timeout. In seconds. */
@@ -79,7 +79,7 @@  static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
 			break;
 		}
 
-		task = sas_alloc_task(GFP_KERNEL);
+		task = sas_alloc_slow_task(GFP_KERNEL);
 		if (!task) {
 			res = -ENOMEM;
 			break;
@@ -91,20 +91,20 @@  static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
 
 		task->task_done = smp_task_done;
 
-		task->timer.data = (unsigned long) task;
-		task->timer.function = smp_task_timedout;
-		task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
-		add_timer(&task->timer);
+		task->slow_task->timer.data = (unsigned long) task;
+		task->slow_task->timer.function = smp_task_timedout;
+		task->slow_task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
+		add_timer(&task->slow_task->timer);
 
 		res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
 
 		if (res) {
-			del_timer(&task->timer);
+			del_timer(&task->slow_task->timer);
 			SAS_DPRINTK("executing SMP task failed:%d\n", res);
 			break;
 		}
 
-		wait_for_completion(&task->completion);
+		wait_for_completion(&task->slow_task->completion);
 		res = -ECOMM;
 		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
 			SAS_DPRINTK("smp task timed out or aborted\n");
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 2fc23d3..57e7ac9 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -48,18 +48,37 @@  struct sas_task *sas_alloc_task(gfp_t flags)
 		INIT_LIST_HEAD(&task->list);
 		spin_lock_init(&task->task_state_lock);
 		task->task_state_flags = SAS_TASK_STATE_PENDING;
-		init_timer(&task->timer);
-		init_completion(&task->completion);
 	}
 
 	return task;
 }
 EXPORT_SYMBOL_GPL(sas_alloc_task);
 
+struct sas_task *sas_alloc_slow_task(gfp_t flags)
+{
+	struct sas_task *task = sas_alloc_task(flags);
+	struct sas_task_slow *slow = kmalloc(sizeof(*slow), flags);
+
+	if (!task || !slow) {
+		if (task)
+			kmem_cache_free(sas_task_cache, task);
+		kfree(slow);
+		return NULL;
+	}
+
+	task->slow_task = slow;
+	init_timer(&slow->timer);
+	init_completion(&slow->completion);
+
+	return task;
+}
+EXPORT_SYMBOL_GPL(sas_alloc_slow_task);
+
 void sas_free_task(struct sas_task *task)
 {
 	if (task) {
 		BUG_ON(!list_empty(&task->list));
+		kfree(task->slow_task);
 		kmem_cache_free(sas_task_cache, task);
 	}
 }
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 86ffd8f..9716f2e 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -1013,9 +1013,13 @@  void sas_task_abort(struct sas_task *task)
 
 	/* Escape for libsas internal commands */
 	if (!sc) {
-		if (!del_timer(&task->timer))
+		struct sas_task_slow *slow = task->slow_task;
+
+		if (!slow)
+			return;
+		if (!del_timer(&slow->timer))
 			return;
-		task->timer.function(task->timer.data);
+		slow->timer.function(slow->timer.data);
 		return;
 	}
 
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index b68a653..d0462b8 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -1365,9 +1365,9 @@  void mvs_dev_gone(struct domain_device *dev)
 
 static void mvs_task_done(struct sas_task *task)
 {
-	if (!del_timer(&task->timer))
+	if (!del_timer(&task->slow_task->timer))
 		return;
-	complete(&task->completion);
+	complete(&task->slow_task->completion);
 }
 
 static void mvs_tmf_timedout(unsigned long data)
@@ -1375,7 +1375,7 @@  static void mvs_tmf_timedout(unsigned long data)
 	struct sas_task *task = (struct sas_task *)data;
 
 	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
-	complete(&task->completion);
+	complete(&task->slow_task->completion);
 }
 
 #define MVS_TASK_TIMEOUT 20
@@ -1386,7 +1386,7 @@  static int mvs_exec_internal_tmf_task(struct domain_device *dev,
 	struct sas_task *task = NULL;
 
 	for (retry = 0; retry < 3; retry++) {
-		task = sas_alloc_task(GFP_KERNEL);
+		task = sas_alloc_slow_task(GFP_KERNEL);
 		if (!task)
 			return -ENOMEM;
 
@@ -1396,20 +1396,20 @@  static int mvs_exec_internal_tmf_task(struct domain_device *dev,
 		memcpy(&task->ssp_task, parameter, para_len);
 		task->task_done = mvs_task_done;
 
-		task->timer.data = (unsigned long) task;
-		task->timer.function = mvs_tmf_timedout;
-		task->timer.expires = jiffies + MVS_TASK_TIMEOUT*HZ;
-		add_timer(&task->timer);
+		task->slow_task->timer.data = (unsigned long) task;
+		task->slow_task->timer.function = mvs_tmf_timedout;
+		task->slow_task->timer.expires = jiffies + MVS_TASK_TIMEOUT*HZ;
+		add_timer(&task->slow_task->timer);
 
 		res = mvs_task_exec(task, 1, GFP_KERNEL, NULL, 1, tmf);
 
 		if (res) {
-			del_timer(&task->timer);
+			del_timer(&task->slow_task->timer);
 			mv_printk("executing internel task failed:%d\n", res);
 			goto ex_err;
 		}
 
-		wait_for_completion(&task->completion);
+		wait_for_completion(&task->slow_task->completion);
 		res = TMF_RESP_FUNC_FAILED;
 		/* Even TMF timed out, return direct. */
 		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index b111018..ad36f1a 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -627,9 +627,9 @@  int pm8001_dev_found(struct domain_device *dev)
 
 static void pm8001_task_done(struct sas_task *task)
 {
-	if (!del_timer(&task->timer))
+	if (!del_timer(&task->slow_task->timer))
 		return;
-	complete(&task->completion);
+	complete(&task->slow_task->completion);
 }
 
 static void pm8001_tmf_timedout(unsigned long data)
@@ -637,7 +637,7 @@  static void pm8001_tmf_timedout(unsigned long data)
 	struct sas_task *task = (struct sas_task *)data;
 
 	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
-	complete(&task->completion);
+	complete(&task->slow_task->completion);
 }
 
 #define PM8001_TASK_TIMEOUT 20
@@ -668,21 +668,21 @@  static int pm8001_exec_internal_tmf_task(struct domain_device *dev,
 		task->task_proto = dev->tproto;
 		memcpy(&task->ssp_task, parameter, para_len);
 		task->task_done = pm8001_task_done;
-		task->timer.data = (unsigned long)task;
-		task->timer.function = pm8001_tmf_timedout;
-		task->timer.expires = jiffies + PM8001_TASK_TIMEOUT*HZ;
-		add_timer(&task->timer);
+		task->slow_task->timer.data = (unsigned long)task;
+		task->slow_task->timer.function = pm8001_tmf_timedout;
+		task->slow_task->timer.expires = jiffies + PM8001_TASK_TIMEOUT*HZ;
+		add_timer(&task->slow_task->timer);
 
 		res = pm8001_task_exec(task, 1, GFP_KERNEL, 1, tmf);
 
 		if (res) {
-			del_timer(&task->timer);
+			del_timer(&task->slow_task->timer);
 			PM8001_FAIL_DBG(pm8001_ha,
 				pm8001_printk("Executing internal task "
 				"failed\n"));
 			goto ex_err;
 		}
-		wait_for_completion(&task->completion);
+		wait_for_completion(&task->slow_task->completion);
 		res = -TMF_RESP_FUNC_FAILED;
 		/* Even TMF timed out, return direct. */
 		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
@@ -749,10 +749,10 @@  pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha,
 		task->dev = dev;
 		task->task_proto = dev->tproto;
 		task->task_done = pm8001_task_done;
-		task->timer.data = (unsigned long)task;
-		task->timer.function = pm8001_tmf_timedout;
-		task->timer.expires = jiffies + PM8001_TASK_TIMEOUT * HZ;
-		add_timer(&task->timer);
+		task->slow_task->timer.data = (unsigned long)task;
+		task->slow_task->timer.function = pm8001_tmf_timedout;
+		task->slow_task->timer.expires = jiffies + PM8001_TASK_TIMEOUT * HZ;
+		add_timer(&task->slow_task->timer);
 
 		res = pm8001_tag_alloc(pm8001_ha, &ccb_tag);
 		if (res)
@@ -766,13 +766,13 @@  pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha,
 			pm8001_dev, flag, task_tag, ccb_tag);
 
 		if (res) {
-			del_timer(&task->timer);
+			del_timer(&task->slow_task->timer);
 			PM8001_FAIL_DBG(pm8001_ha,
 				pm8001_printk("Executing internal task "
 				"failed\n"));
 			goto ex_err;
 		}
-		wait_for_completion(&task->completion);
+		wait_for_completion(&task->slow_task->completion);
 		res = TMF_RESP_FUNC_FAILED;
 		/* Even TMF timed out, return direct. */
 		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 484bc52..4e84ef3 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -568,10 +568,6 @@  struct sas_task {
 
 	enum   sas_protocol      task_proto;
 
-	/* Used by the discovery code. */
-	struct timer_list     timer;
-	struct completion     completion;
-
 	union {
 		struct sas_ata_task ata_task;
 		struct sas_smp_task smp_task;
@@ -588,8 +584,15 @@  struct sas_task {
 
 	void   *lldd_task;	  /* for use by LLDDs */
 	void   *uldd_task;
+	struct sas_task_slow *slow_task;
+};
 
-	struct work_struct abort_work;
+struct sas_task_slow {
+	/* standard/extra infrastructure for slow path commands (SMP and
+	 * internal lldd commands
+	 */
+	struct timer_list     timer;
+	struct completion     completion;
 };
 
 #define SAS_TASK_STATE_PENDING      1
@@ -599,6 +602,7 @@  struct sas_task {
 #define SAS_TASK_AT_INITIATOR       16
 
 extern struct sas_task *sas_alloc_task(gfp_t flags);
+extern struct sas_task *sas_alloc_slow_task(gfp_t flags);
 extern void sas_free_task(struct sas_task *task);
 
 struct sas_domain_function_template {