isci: combine request flags
[profile/ivi/kernel-adaptation-intel-automotive.git] / drivers / scsi / isci / request.c
index ebe160c..27376ba 100644 (file)
 #include "scu_event_codes.h"
 #include "sas.h"
 
-/**
- * This method returns the sgl element pair for the specificed sgl_pair index.
- * @sci_req: This parameter specifies the IO request for which to retrieve
- *    the Scatter-Gather List element pair.
- * @sgl_pair_index: This parameter specifies the index into the SGL element
- *    pair to be retrieved.
- *
- * This method returns a pointer to an struct scu_sgl_element_pair.
- */
-static struct scu_sgl_element_pair *scic_sds_request_get_sgl_element_pair(
-       struct scic_sds_request *sci_req,
-       u32 sgl_pair_index
-       ) {
-       struct scu_task_context *task_context;
+static struct scu_sgl_element_pair *to_sgl_element_pair(struct scic_sds_request *sci_req,
+                                                       int idx)
+{
+       if (idx == 0)
+               return &sci_req->tc->sgl_pair_ab;
+       else if (idx == 1)
+               return &sci_req->tc->sgl_pair_cd;
+       else if (idx < 0)
+               return NULL;
+       else
+               return &sci_req->sg_table[idx - 2];
+}
 
-       task_context = (struct scu_task_context *)sci_req->task_context_buffer;
+static dma_addr_t to_sgl_element_pair_dma(struct scic_sds_controller *scic,
+                                         struct scic_sds_request *sci_req, u32 idx)
+{
+       u32 offset;
 
-       if (sgl_pair_index == 0) {
-               return &task_context->sgl_pair_ab;
-       } else if (sgl_pair_index == 1) {
-               return &task_context->sgl_pair_cd;
+       if (idx == 0) {
+               offset = (void *) &sci_req->tc->sgl_pair_ab -
+                        (void *) &scic->task_context_table[0];
+               return scic->task_context_dma + offset;
+       } else if (idx == 1) {
+               offset = (void *) &sci_req->tc->sgl_pair_cd -
+                        (void *) &scic->task_context_table[0];
+               return scic->task_context_dma + offset;
        }
 
-       return &sci_req->sg_table[sgl_pair_index - 2];
+       return scic_io_request_get_dma_addr(sci_req, &sci_req->sg_table[idx - 2]);
+}
+
+static void init_sgl_element(struct scu_sgl_element *e, struct scatterlist *sg)
+{
+       e->length = sg_dma_len(sg);
+       e->address_upper = upper_32_bits(sg_dma_address(sg));
+       e->address_lower = lower_32_bits(sg_dma_address(sg));
+       e->address_modifier = 0;
 }
 
-/**
- * This function will build the SGL list for an IO request.
- * @sci_req: This parameter specifies the IO request for which to build
- *    the Scatter-Gather List.
- *
- */
 static void scic_sds_request_build_sgl(struct scic_sds_request *sds_request)
 {
        struct isci_request *isci_request = sci_req_to_ireq(sds_request);
        struct isci_host *isci_host = isci_request->isci_host;
+       struct scic_sds_controller *scic = &isci_host->sci;
        struct sas_task *task = isci_request_access_task(isci_request);
        struct scatterlist *sg = NULL;
        dma_addr_t dma_addr;
@@ -108,25 +116,19 @@ static void scic_sds_request_build_sgl(struct scic_sds_request *sds_request)
                sg = task->scatter;
 
                while (sg) {
-                       scu_sg = scic_sds_request_get_sgl_element_pair(
-                                       sds_request,
-                                       sg_idx);
-
-                       SCU_SGL_COPY(scu_sg->A, sg);
-
+                       scu_sg = to_sgl_element_pair(sds_request, sg_idx);
+                       init_sgl_element(&scu_sg->A, sg);
                        sg = sg_next(sg);
-
                        if (sg) {
-                               SCU_SGL_COPY(scu_sg->B, sg);
+                               init_sgl_element(&scu_sg->B, sg);
                                sg = sg_next(sg);
                        } else
-                               SCU_SGL_ZERO(scu_sg->B);
+                               memset(&scu_sg->B, 0, sizeof(scu_sg->B));
 
                        if (prev_sg) {
-                               dma_addr =
-                                       scic_io_request_get_dma_addr(
-                                                       sds_request,
-                                                       scu_sg);
+                               dma_addr = to_sgl_element_pair_dma(scic,
+                                                                  sds_request,
+                                                                  sg_idx);
 
                                prev_sg->next_pair_upper =
                                        upper_32_bits(dma_addr);
@@ -138,8 +140,7 @@ static void scic_sds_request_build_sgl(struct scic_sds_request *sds_request)
                        sg_idx++;
                }
        } else {        /* handle when no sg */
-               scu_sg = scic_sds_request_get_sgl_element_pair(sds_request,
-                                                              sg_idx);
+               scu_sg = to_sgl_element_pair(sds_request, sg_idx);
 
                dma_addr = dma_map_single(&isci_host->pdev->dev,
                                          task->scatter,
@@ -246,35 +247,12 @@ static void scu_ssp_reqeust_construct_task_context(
        /* task_context->type.ssp.tag = sci_req->io_tag; */
        task_context->task_phase = 0x01;
 
-       if (sds_request->was_tag_assigned_by_user) {
-               /*
-                * Build the task context now since we have already read
-                * the data
-                */
-               sds_request->post_context =
-                       (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC |
-                        (scic_sds_controller_get_protocol_engine_group(
-                                                       controller) <<
-                         SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) |
-                        (scic_sds_port_get_index(target_port) <<
-                         SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) |
-                         ISCI_TAG_TCI(sds_request->io_tag));
-       } else {
-               /*
-                * Build the task context now since we have already read
-                * the data
-                *
-                * I/O tag index is not assigned because we have to wait
-                * until we get a TCi
-                */
-               sds_request->post_context =
-                       (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC |
-                        (scic_sds_controller_get_protocol_engine_group(
-                                                       owning_controller) <<
-                         SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) |
-                        (scic_sds_port_get_index(target_port) <<
-                         SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT));
-       }
+       sds_request->post_context = (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC |
+                                    (scic_sds_controller_get_protocol_engine_group(controller) <<
+                                     SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) |
+                                    (scic_sds_port_get_index(target_port) <<
+                                     SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) |
+                                    ISCI_TAG_TCI(sds_request->io_tag));
 
        /*
         * Copy the physical address for the command buffer to the
@@ -302,14 +280,11 @@ static void scu_ssp_reqeust_construct_task_context(
  * @sci_req:
  *
  */
-static void scu_ssp_io_request_construct_task_context(
-       struct scic_sds_request *sci_req,
-       enum dma_data_direction dir,
-       u32 len)
+static void scu_ssp_io_request_construct_task_context(struct scic_sds_request *sci_req,
+                                                     enum dma_data_direction dir,
+                                                     u32 len)
 {
-       struct scu_task_context *task_context;
-
-       task_context = scic_sds_request_get_task_context(sci_req);
+       struct scu_task_context *task_context = sci_req->tc;
 
        scu_ssp_reqeust_construct_task_context(sci_req, task_context);
 
@@ -347,12 +322,9 @@ static void scu_ssp_io_request_construct_task_context(
  *    constructed.
  *
  */
-static void scu_ssp_task_request_construct_task_context(
-       struct scic_sds_request *sci_req)
+static void scu_ssp_task_request_construct_task_context(struct scic_sds_request *sci_req)
 {
-       struct scu_task_context *task_context;
-
-       task_context = scic_sds_request_get_task_context(sci_req);
+       struct scu_task_context *task_context = sci_req->tc;
 
        scu_ssp_reqeust_construct_task_context(sci_req, task_context);
 
@@ -421,35 +393,12 @@ static void scu_sata_reqeust_construct_task_context(
        /* Set the first word of the H2D REG FIS */
        task_context->type.words[0] = *(u32 *)&sci_req->stp.cmd;
 
-       if (sci_req->was_tag_assigned_by_user) {
-               /*
-                * Build the task context now since we have already read
-                * the data
-                */
-               sci_req->post_context =
-                       (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC |
-                        (scic_sds_controller_get_protocol_engine_group(
-                                                       controller) <<
-                         SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) |
-                        (scic_sds_port_get_index(target_port) <<
-                         SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) |
-                         ISCI_TAG_TCI(sci_req->io_tag));
-       } else {
-               /*
-                * Build the task context now since we have already read
-                * the data.
-                * I/O tag index is not assigned because we have to wait
-                * until we get a TCi.
-                */
-               sci_req->post_context =
-                       (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC |
-                        (scic_sds_controller_get_protocol_engine_group(
-                                                       controller) <<
-                         SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) |
-                        (scic_sds_port_get_index(target_port) <<
-                         SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT));
-       }
-
+       sci_req->post_context = (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC |
+                                (scic_sds_controller_get_protocol_engine_group(controller) <<
+                                 SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) |
+                                (scic_sds_port_get_index(target_port) <<
+                                 SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) |
+                                ISCI_TAG_TCI(sci_req->io_tag));
        /*
         * Copy the physical address for the command buffer to the SCU Task
         * Context. We must offset the command buffer by 4 bytes because the
@@ -467,22 +416,9 @@ static void scu_sata_reqeust_construct_task_context(
        task_context->response_iu_lower = 0;
 }
 
-
-
-/**
- * scu_stp_raw_request_construct_task_context -
- * @sci_req: This parameter specifies the STP request object for which to
- *    construct a RAW command frame task context.
- * @task_context: This parameter specifies the SCU specific task context buffer
- *    to construct.
- *
- * This method performs the operations common to all SATA/STP requests
- * utilizing the raw frame method. none
- */
-static void scu_stp_raw_request_construct_task_context(struct scic_sds_stp_request *stp_req,
-                                                      struct scu_task_context *task_context)
+static void scu_stp_raw_request_construct_task_context(struct scic_sds_request *sci_req)
 {
-       struct scic_sds_request *sci_req = to_sci_req(stp_req);
+       struct scu_task_context *task_context = sci_req->tc;
 
        scu_sata_reqeust_construct_task_context(sci_req, task_context);
 
@@ -500,8 +436,7 @@ scic_sds_stp_pio_request_construct(struct scic_sds_request *sci_req,
        struct scic_sds_stp_request *stp_req = &sci_req->stp.req;
        struct scic_sds_stp_pio_request *pio = &stp_req->type.pio;
 
-       scu_stp_raw_request_construct_task_context(stp_req,
-                                                  sci_req->task_context_buffer);
+       scu_stp_raw_request_construct_task_context(sci_req);
 
        pio->current_transfer_bytes = 0;
        pio->ending_error = 0;
@@ -512,13 +447,10 @@ scic_sds_stp_pio_request_construct(struct scic_sds_request *sci_req,
 
        if (copy_rx_frame) {
                scic_sds_request_build_sgl(sci_req);
-               /* Since the IO request copy of the TC contains the same data as
-                * the actual TC this pointer is vaild for either.
-                */
-               pio->request_current.sgl_pair = &sci_req->task_context_buffer->sgl_pair_ab;
+               pio->request_current.sgl_index = 0;
        } else {
                /* The user does not want the data copied to the SGL buffer location */
-               pio->request_current.sgl_pair = NULL;
+               pio->request_current.sgl_index = -1;
        }
 
        return SCI_SUCCESS;
@@ -541,7 +473,7 @@ static void scic_sds_stp_optimized_request_construct(struct scic_sds_request *sc
                                                     u32 len,
                                                     enum dma_data_direction dir)
 {
-       struct scu_task_context *task_context = sci_req->task_context_buffer;
+       struct scu_task_context *task_context = sci_req->tc;
 
        /* Build the STP task context structure */
        scu_sata_reqeust_construct_task_context(sci_req, task_context);
@@ -587,8 +519,7 @@ scic_io_request_construct_sata(struct scic_sds_request *sci_req,
 
                if (tmf->tmf_code == isci_tmf_sata_srst_high ||
                    tmf->tmf_code == isci_tmf_sata_srst_low) {
-                       scu_stp_raw_request_construct_task_context(&sci_req->stp.req,
-                                                                  sci_req->task_context_buffer);
+                       scu_stp_raw_request_construct_task_context(sci_req);
                        return SCI_SUCCESS;
                } else {
                        dev_err(scic_to_dev(sci_req->owning_controller),
@@ -611,8 +542,7 @@ scic_io_request_construct_sata(struct scic_sds_request *sci_req,
 
        /* non data */
        if (task->data_dir == DMA_NONE) {
-               scu_stp_raw_request_construct_task_context(&sci_req->stp.req,
-                                                          sci_req->task_context_buffer);
+               scu_stp_raw_request_construct_task_context(sci_req);
                return SCI_SUCCESS;
        }
 
@@ -701,8 +631,7 @@ enum sci_status scic_task_request_construct_sata(struct scic_sds_request *sci_re
 
                if (tmf->tmf_code == isci_tmf_sata_srst_high ||
                    tmf->tmf_code == isci_tmf_sata_srst_low) {
-                       scu_stp_raw_request_construct_task_context(&sci_req->stp.req,
-                                                                  sci_req->task_context_buffer);
+                       scu_stp_raw_request_construct_task_context(sci_req);
                } else {
                        dev_err(scic_to_dev(sci_req->owning_controller),
                                "%s: Request 0x%p received un-handled SAT "
@@ -749,9 +678,9 @@ static u32 sci_req_tx_bytes(struct scic_sds_request *sci_req)
 
 enum sci_status scic_sds_request_start(struct scic_sds_request *sci_req)
 {
-       struct scic_sds_controller *scic = sci_req->owning_controller;
-       struct scu_task_context *task_context;
        enum sci_base_request_states state;
+       struct scu_task_context *tc = sci_req->tc;
+       struct scic_sds_controller *scic = sci_req->owning_controller;
 
        state = sci_req->sm.current_state_id;
        if (state != SCI_REQ_CONSTRUCTED) {
@@ -761,61 +690,39 @@ enum sci_status scic_sds_request_start(struct scic_sds_request *sci_req)
                return SCI_FAILURE_INVALID_STATE;
        }
 
-       /* if necessary, allocate a TCi for the io request object and then will,
-        * if necessary, copy the constructed TC data into the actual TC buffer.
-        * If everything is successful the post context field is updated with
-        * the TCi so the controller can post the request to the hardware.
-        */
-       if (sci_req->io_tag == SCI_CONTROLLER_INVALID_IO_TAG)
-               sci_req->io_tag = scic_controller_allocate_io_tag(scic);
-
-       /* Record the IO Tag in the request */
-       if (sci_req->io_tag != SCI_CONTROLLER_INVALID_IO_TAG) {
-               task_context = sci_req->task_context_buffer;
-
-               task_context->task_index = ISCI_TAG_TCI(sci_req->io_tag);
-
-               switch (task_context->protocol_type) {
-               case SCU_TASK_CONTEXT_PROTOCOL_SMP:
-               case SCU_TASK_CONTEXT_PROTOCOL_SSP:
-                       /* SSP/SMP Frame */
-                       task_context->type.ssp.tag = sci_req->io_tag;
-                       task_context->type.ssp.target_port_transfer_tag =
-                               0xFFFF;
-                       break;
+       tc->task_index = ISCI_TAG_TCI(sci_req->io_tag);
 
-               case SCU_TASK_CONTEXT_PROTOCOL_STP:
-                       /* STP/SATA Frame
-                        * task_context->type.stp.ncq_tag = sci_req->ncq_tag;
-                        */
-                       break;
-
-               case SCU_TASK_CONTEXT_PROTOCOL_NONE:
-                       /* / @todo When do we set no protocol type? */
-                       break;
+       switch (tc->protocol_type) {
+       case SCU_TASK_CONTEXT_PROTOCOL_SMP:
+       case SCU_TASK_CONTEXT_PROTOCOL_SSP:
+               /* SSP/SMP Frame */
+               tc->type.ssp.tag = sci_req->io_tag;
+               tc->type.ssp.target_port_transfer_tag = 0xFFFF;
+               break;
 
-               default:
-                       /* This should never happen since we build the IO
-                        * requests */
-                       break;
-               }
+       case SCU_TASK_CONTEXT_PROTOCOL_STP:
+               /* STP/SATA Frame
+                * tc->type.stp.ncq_tag = sci_req->ncq_tag;
+                */
+               break;
 
-               /*
-                * Check to see if we need to copy the task context buffer
-                * or have been building into the task context buffer */
-               if (sci_req->was_tag_assigned_by_user == false)
-                       scic_sds_controller_copy_task_context(scic, sci_req);
+       case SCU_TASK_CONTEXT_PROTOCOL_NONE:
+               /* / @todo When do we set no protocol type? */
+               break;
 
-               /* Add to the post_context the io tag value */
-               sci_req->post_context |= ISCI_TAG_TCI(sci_req->io_tag);
+       default:
+               /* This should never happen since we build the IO
+                * requests */
+               break;
+       }
 
-               /* Everything is good go ahead and change state */
-               sci_change_state(&sci_req->sm, SCI_REQ_STARTED);
+       /* Add to the post_context the io tag value */
+       sci_req->post_context |= ISCI_TAG_TCI(sci_req->io_tag);
 
-               return SCI_SUCCESS;
-       }
+       /* Everything is good go ahead and change state */
+       sci_change_state(&sci_req->sm, SCI_REQ_STARTED);
 
-       return SCI_FAILURE_INSUFFICIENT_RESOURCES;
+       return SCI_SUCCESS;
 }
 
 enum sci_status
@@ -880,9 +787,6 @@ enum sci_status scic_sds_request_complete(struct scic_sds_request *sci_req)
                      "isci: request completion from wrong state (%d)\n", state))
                return SCI_FAILURE_INVALID_STATE;
 
-       if (!sci_req->was_tag_assigned_by_user)
-               scic_controller_free_io_tag(scic, sci_req->io_tag);
-
        if (sci_req->saved_rx_frame_index != SCU_INVALID_FRAME_INDEX)
                scic_sds_controller_release_frame(scic,
                                                  sci_req->saved_rx_frame_index);
@@ -1244,51 +1148,40 @@ void scic_stp_io_request_set_ncq_tag(struct scic_sds_request *req,
         * @note This could be made to return an error to the user if the user
         *       attempts to set the NCQ tag in the wrong state.
         */
-       req->task_context_buffer->type.stp.ncq_tag = ncq_tag;
+       req->tc->type.stp.ncq_tag = ncq_tag;
 }
 
-/**
- *
- * @sci_req:
- *
- * Get the next SGL element from the request. - Check on which SGL element pair
- * we are working - if working on SLG pair element A - advance to element B -
- * else - check to see if there are more SGL element pairs for this IO request
- * - if there are more SGL element pairs - advance to the next pair and return
- * element A struct scu_sgl_element*
- */
-static struct scu_sgl_element *scic_sds_stp_request_pio_get_next_sgl(struct scic_sds_stp_request *stp_req)
+static struct scu_sgl_element *pio_sgl_next(struct scic_sds_stp_request *stp_req)
 {
-       struct scu_sgl_element *current_sgl;
+       struct scu_sgl_element *sgl;
+       struct scu_sgl_element_pair *sgl_pair;
        struct scic_sds_request *sci_req = to_sci_req(stp_req);
        struct scic_sds_request_pio_sgl *pio_sgl = &stp_req->type.pio.request_current;
 
-       if (pio_sgl->sgl_set == SCU_SGL_ELEMENT_PAIR_A) {
-               if (pio_sgl->sgl_pair->B.address_lower == 0 &&
-                   pio_sgl->sgl_pair->B.address_upper == 0) {
-                       current_sgl = NULL;
+       sgl_pair = to_sgl_element_pair(sci_req, pio_sgl->sgl_index);
+       if (!sgl_pair)
+               sgl = NULL;
+       else if (pio_sgl->sgl_set == SCU_SGL_ELEMENT_PAIR_A) {
+               if (sgl_pair->B.address_lower == 0 &&
+                   sgl_pair->B.address_upper == 0) {
+                       sgl = NULL;
                } else {
                        pio_sgl->sgl_set = SCU_SGL_ELEMENT_PAIR_B;
-                       current_sgl = &pio_sgl->sgl_pair->B;
+                       sgl = &sgl_pair->B;
                }
        } else {
-               if (pio_sgl->sgl_pair->next_pair_lower == 0 &&
-                   pio_sgl->sgl_pair->next_pair_upper == 0) {
-                       current_sgl = NULL;
+               if (sgl_pair->next_pair_lower == 0 &&
+                   sgl_pair->next_pair_upper == 0) {
+                       sgl = NULL;
                } else {
-                       u64 phys_addr;
-
-                       phys_addr = pio_sgl->sgl_pair->next_pair_upper;
-                       phys_addr <<= 32;
-                       phys_addr |= pio_sgl->sgl_pair->next_pair_lower;
-
-                       pio_sgl->sgl_pair = scic_request_get_virt_addr(sci_req, phys_addr);
+                       pio_sgl->sgl_index++;
                        pio_sgl->sgl_set = SCU_SGL_ELEMENT_PAIR_A;
-                       current_sgl = &pio_sgl->sgl_pair->A;
+                       sgl_pair = to_sgl_element_pair(sci_req, pio_sgl->sgl_index);
+                       sgl = &sgl_pair->A;
                }
        }
 
-       return current_sgl;
+       return sgl;
 }
 
 static enum sci_status
@@ -1328,21 +1221,19 @@ static enum sci_status scic_sds_stp_request_pio_data_out_trasmit_data_frame(
        struct scic_sds_request *sci_req,
        u32 length)
 {
-       struct scic_sds_controller *scic = sci_req->owning_controller;
        struct scic_sds_stp_request *stp_req = &sci_req->stp.req;
-       struct scu_task_context *task_context;
+       struct scu_task_context *task_context = sci_req->tc;
+       struct scu_sgl_element_pair *sgl_pair;
        struct scu_sgl_element *current_sgl;
 
        /* Recycle the TC and reconstruct it for sending out DATA FIS containing
         * for the data from current_sgl+offset for the input length
         */
-       task_context = scic_sds_controller_get_task_context_buffer(scic,
-                                                                  sci_req->io_tag);
-
+       sgl_pair = to_sgl_element_pair(sci_req, stp_req->type.pio.request_current.sgl_index);
        if (stp_req->type.pio.request_current.sgl_set == SCU_SGL_ELEMENT_PAIR_A)
-               current_sgl = &stp_req->type.pio.request_current.sgl_pair->A;
+               current_sgl = &sgl_pair->A;
        else
-               current_sgl = &stp_req->type.pio.request_current.sgl_pair->B;
+               current_sgl = &sgl_pair->B;
 
        /* update the TC */
        task_context->command_iu_upper = current_sgl->address_upper;
@@ -1362,18 +1253,21 @@ static enum sci_status scic_sds_stp_request_pio_data_out_transmit_data(struct sc
        u32 remaining_bytes_in_current_sgl = 0;
        enum sci_status status = SCI_SUCCESS;
        struct scic_sds_stp_request *stp_req = &sci_req->stp.req;
+       struct scu_sgl_element_pair *sgl_pair;
 
        sgl_offset = stp_req->type.pio.request_current.sgl_offset;
+       sgl_pair = to_sgl_element_pair(sci_req, stp_req->type.pio.request_current.sgl_index);
+       if (WARN_ONCE(!sgl_pair, "%s: null sgl element", __func__))
+               return SCI_FAILURE;
 
        if (stp_req->type.pio.request_current.sgl_set == SCU_SGL_ELEMENT_PAIR_A) {
-               current_sgl = &(stp_req->type.pio.request_current.sgl_pair->A);
-               remaining_bytes_in_current_sgl = stp_req->type.pio.request_current.sgl_pair->A.length - sgl_offset;
+               current_sgl = &sgl_pair->A;
+               remaining_bytes_in_current_sgl = sgl_pair->A.length - sgl_offset;
        } else {
-               current_sgl = &(stp_req->type.pio.request_current.sgl_pair->B);
-               remaining_bytes_in_current_sgl = stp_req->type.pio.request_current.sgl_pair->B.length - sgl_offset;
+               current_sgl = &sgl_pair->B;
+               remaining_bytes_in_current_sgl = sgl_pair->B.length - sgl_offset;
        }
 
-
        if (stp_req->type.pio.pio_transfer_bytes > 0) {
                if (stp_req->type.pio.pio_transfer_bytes >= remaining_bytes_in_current_sgl) {
                        /* recycle the TC and send the H2D Data FIS from (current sgl + sgl_offset) and length = remaining_bytes_in_current_sgl */
@@ -1382,7 +1276,7 @@ static enum sci_status scic_sds_stp_request_pio_data_out_transmit_data(struct sc
                                stp_req->type.pio.pio_transfer_bytes -= remaining_bytes_in_current_sgl;
 
                                /* update the current sgl, sgl_offset and save for future */
-                               current_sgl = scic_sds_stp_request_pio_get_next_sgl(stp_req);
+                               current_sgl = pio_sgl_next(stp_req);
                                sgl_offset = 0;
                        }
                } else if (stp_req->type.pio.pio_transfer_bytes < remaining_bytes_in_current_sgl) {
@@ -1694,7 +1588,7 @@ scic_sds_io_request_frame_handler(struct scic_sds_request *sci_req,
                                                                      frame_index,
                                                                      &smp_resp);
 
-                       word_cnt = (sizeof(struct smp_req) - SMP_RESP_HDR_SZ) /
+                       word_cnt = (sizeof(struct smp_resp) - SMP_RESP_HDR_SZ) /
                                sizeof(u32);
 
                        sci_swab32_cpy(((u8 *) rsp_hdr) + SMP_RESP_HDR_SZ,
@@ -1945,7 +1839,7 @@ scic_sds_io_request_frame_handler(struct scic_sds_request *sci_req,
                        return status;
                }
 
-               if (stp_req->type.pio.request_current.sgl_pair == NULL) {
+               if (stp_req->type.pio.request_current.sgl_index < 0) {
                        sci_req->saved_rx_frame_index = frame_index;
                        stp_req->type.pio.pio_transfer_bytes = 0;
                } else {
@@ -2289,7 +2183,7 @@ static void isci_request_set_open_reject_status(
        enum sas_open_rej_reason open_rej_reason)
 {
        /* Task in the target is done. */
-       request->complete_in_target       = true;
+       set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
        *response_ptr                     = SAS_TASK_UNDELIVERED;
        *status_ptr                       = SAS_OPEN_REJECT;
        *complete_to_host_ptr             = isci_perform_normal_io_completion;
@@ -2354,7 +2248,7 @@ static void isci_request_handle_controller_specific_errors(
                        else
                                *status_ptr = SAS_ABORTED_TASK;
 
-                       request->complete_in_target = true;
+                       set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
 
                        *complete_to_host_ptr =
                                isci_perform_normal_io_completion;
@@ -2367,7 +2261,7 @@ static void isci_request_handle_controller_specific_errors(
                        else
                                *status_ptr = SAM_STAT_TASK_ABORTED;
 
-                       request->complete_in_target = false;
+                       clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
 
                        *complete_to_host_ptr =
                                isci_perform_error_io_completion;
@@ -2398,7 +2292,7 @@ static void isci_request_handle_controller_specific_errors(
                else
                        *status_ptr = SAS_ABORTED_TASK;
 
-               request->complete_in_target = true;
+               set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
 
                *complete_to_host_ptr = isci_perform_normal_io_completion;
                break;
@@ -2503,11 +2397,11 @@ static void isci_request_handle_controller_specific_errors(
                *status_ptr = SAM_STAT_TASK_ABORTED;
 
                if (task->task_proto == SAS_PROTOCOL_SMP) {
-                       request->complete_in_target = true;
+                       set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
 
                        *complete_to_host_ptr = isci_perform_normal_io_completion;
                } else {
-                       request->complete_in_target = false;
+                       clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
 
                        *complete_to_host_ptr = isci_perform_error_io_completion;
                }
@@ -2658,7 +2552,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
                 *
                 * The target is still there (since the TMF was successful).
                 */
-               request->complete_in_target = true;
+               set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
                response = SAS_TASK_COMPLETE;
 
                /* See if the device has been/is being stopped. Note
@@ -2685,7 +2579,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
                 * Aborting also means an external thread is explicitly managing
                 * this request, so that we do not complete it up the stack.
                 */
-               request->complete_in_target = true;
+               set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
                response = SAS_TASK_UNDELIVERED;
 
                if (!idev)
@@ -2711,7 +2605,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
                 * the device (reset, tear down, etc.), and the I/O needs
                 * to be completed up the stack.
                 */
-               request->complete_in_target = true;
+               set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
                response = SAS_TASK_UNDELIVERED;
 
                /* See if the device has been/is being stopped. Note
@@ -2781,7 +2675,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
                        /* use the task status set in the task struct by the
                         * isci_request_process_response_iu call.
                         */
-                       request->complete_in_target = true;
+                       set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
                        response = task->task_status.resp;
                        status = task->task_status.stat;
                        break;
@@ -2791,7 +2685,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
 
                        response = SAS_TASK_COMPLETE;
                        status   = SAM_STAT_GOOD;
-                       request->complete_in_target = true;
+                       set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
 
                        if (task->task_proto == SAS_PROTOCOL_SMP) {
                                void *rsp = &request->sci.smp.rsp;
@@ -2843,7 +2737,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
                        /* The request was terminated explicitly.  No handling
                         * is needed in the SCSI error handler path.
                         */
-                       request->complete_in_target = true;
+                       set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
                        response = SAS_TASK_UNDELIVERED;
 
                        /* See if the device has been/is being stopped. Note
@@ -2883,7 +2777,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
                        status = SAM_STAT_TASK_ABORTED;
 
                        complete_to_host = isci_perform_error_io_completion;
-                       request->complete_in_target = false;
+                       clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
                        break;
 
                case SCI_FAILURE_RETRY_REQUIRED:
@@ -2896,7 +2790,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
                                status = SAS_ABORTED_TASK;
 
                        complete_to_host = isci_perform_normal_io_completion;
-                       request->complete_in_target = true;
+                       set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
                        break;
 
 
@@ -2919,10 +2813,10 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
                                status = SAS_ABORTED_TASK;
 
                        if (SAS_PROTOCOL_SMP == task->task_proto) {
-                               request->complete_in_target = true;
+                               set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
                                complete_to_host = isci_perform_normal_io_completion;
                        } else {
-                               request->complete_in_target = false;
+                               clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
                                complete_to_host = isci_perform_error_io_completion;
                        }
                        break;
@@ -2930,7 +2824,36 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
                break;
        }
 
-       isci_request_unmap_sgl(request, isci_host->pdev);
+       switch (task->task_proto) {
+       case SAS_PROTOCOL_SSP:
+               if (task->data_dir == DMA_NONE)
+                       break;
+               if (task->num_scatter == 0)
+                       /* 0 indicates a single dma address */
+                       dma_unmap_single(&isci_host->pdev->dev,
+                                        request->zero_scatter_daddr,
+                                        task->total_xfer_len, task->data_dir);
+               else  /* unmap the sgl dma addresses */
+                       dma_unmap_sg(&isci_host->pdev->dev, task->scatter,
+                                    request->num_sg_entries, task->data_dir);
+               break;
+       case SAS_PROTOCOL_SMP: {
+               struct scatterlist *sg = &task->smp_task.smp_req;
+               struct smp_req *smp_req;
+               void *kaddr;
+
+               dma_unmap_sg(&isci_host->pdev->dev, sg, 1, DMA_TO_DEVICE);
+
+               /* need to swab it back in case the command buffer is re-used */
+               kaddr = kmap_atomic(sg_page(sg), KM_IRQ0);
+               smp_req = kaddr + sg->offset;
+               sci_swab32_cpy(smp_req, smp_req, sg->length / sizeof(u32));
+               kunmap_atomic(kaddr, KM_IRQ0);
+               break;
+       }
+       default:
+               break;
+       }
 
        /* Put the completed request on the correct list */
        isci_task_save_for_upper_layer_completion(isci_host, request, response,
@@ -2947,9 +2870,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
         * terminated again, and to cause any calls into abort
         * task to recognize the already completed case.
         */
-       request->terminated = true;
-
-       isci_host_can_dequeue(isci_host, 1);
+       set_bit(IREQ_TERMINATED, &request->flags);
 }
 
 static void scic_sds_request_started_state_enter(struct sci_base_state_machine *sm)
@@ -2998,7 +2919,7 @@ static void scic_sds_request_completed_state_enter(struct sci_base_state_machine
        struct isci_request *ireq = sci_req_to_ireq(sci_req);
 
        /* Tell the SCI_USER that the IO request is complete */
-       if (sci_req->is_task_management_request == false)
+       if (!test_bit(IREQ_TMF, &ireq->flags))
                isci_request_io_request_complete(ihost, ireq,
                                                 sci_req->sci_status);
        else
@@ -3010,7 +2931,7 @@ static void scic_sds_request_aborting_state_enter(struct sci_base_state_machine
        struct scic_sds_request *sci_req = container_of(sm, typeof(*sci_req), sm);
 
        /* Setting the abort bit in the Task Context is required by the silicon. */
-       sci_req->task_context_buffer->abort = 1;
+       sci_req->tc->abort = 1;
 }
 
 static void scic_sds_stp_request_started_non_data_await_h2d_completion_enter(struct sci_base_state_machine *sm)
@@ -3040,7 +2961,7 @@ static void scic_sds_stp_request_started_soft_reset_await_h2d_asserted_completio
 static void scic_sds_stp_request_started_soft_reset_await_h2d_diagnostic_completion_enter(struct sci_base_state_machine *sm)
 {
        struct scic_sds_request *sci_req = container_of(sm, typeof(*sci_req), sm);
-       struct scu_task_context *task_context;
+       struct scu_task_context *tc = sci_req->tc;
        struct host_to_dev_fis *h2d_fis;
        enum sci_status status;
 
@@ -3049,9 +2970,7 @@ static void scic_sds_stp_request_started_soft_reset_await_h2d_diagnostic_complet
        h2d_fis->control = 0;
 
        /* Clear the TC control bit */
-       task_context = scic_sds_controller_get_task_context_buffer(
-               sci_req->owning_controller, sci_req->io_tag);
-       task_context->control_frame = 0;
+       tc->control_frame = 0;
 
        status = scic_controller_continue_io(sci_req);
        WARN_ONCE(status != SCI_SUCCESS, "isci: continue io failure\n");
@@ -3112,18 +3031,8 @@ scic_sds_general_request_construct(struct scic_sds_controller *scic,
        sci_req->sci_status   = SCI_SUCCESS;
        sci_req->scu_status   = 0;
        sci_req->post_context = 0xFFFFFFFF;
-
-       sci_req->is_task_management_request = false;
-
-       if (io_tag == SCI_CONTROLLER_INVALID_IO_TAG) {
-               sci_req->was_tag_assigned_by_user = false;
-               sci_req->task_context_buffer = &sci_req->tc;
-       } else {
-               sci_req->was_tag_assigned_by_user = true;
-
-               sci_req->task_context_buffer =
-                       scic_sds_controller_get_task_context_buffer(scic, io_tag);
-       }
+       sci_req->tc = &scic->task_context_table[ISCI_TAG_TCI(io_tag)];
+       WARN_ONCE(io_tag == SCI_CONTROLLER_INVALID_IO_TAG, "straggling invalid tag usage\n");
 }
 
 static enum sci_status
@@ -3145,12 +3054,11 @@ scic_io_request_construct(struct scic_sds_controller *scic,
        else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP))
                memset(&sci_req->stp.cmd, 0, sizeof(sci_req->stp.cmd));
        else if (dev_is_expander(dev))
-               memset(&sci_req->smp.cmd, 0, sizeof(sci_req->smp.cmd));
+               /* pass */;
        else
                return SCI_FAILURE_UNSUPPORTED_PROTOCOL;
 
-       memset(sci_req->task_context_buffer, 0,
-              offsetof(struct scu_task_context, sgl_pair_ab));
+       memset(sci_req->tc, 0, offsetof(struct scu_task_context, sgl_pair_ab));
 
        return status;
 }
@@ -3167,8 +3075,8 @@ enum sci_status scic_task_request_construct(struct scic_sds_controller *scic,
 
        if (dev->dev_type == SAS_END_DEV ||
            dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) {
-               sci_req->is_task_management_request = true;
-               memset(sci_req->task_context_buffer, 0, sizeof(struct scu_task_context));
+               set_bit(IREQ_TMF, &sci_req_to_ireq(sci_req)->flags);
+               memset(sci_req->tc, 0, sizeof(struct scu_task_context));
        } else
                status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
 
@@ -3221,32 +3129,56 @@ static enum sci_status isci_request_stp_request_construct(
        return status;
 }
 
-/*
- * This function will fill in the SCU Task Context for a SMP request. The
- *    following important settings are utilized: -# task_type ==
- *    SCU_TASK_TYPE_SMP.  This simply indicates that a normal request type
- *    (i.e. non-raw frame) is being utilized to perform task management. -#
- *    control_frame == 1.  This ensures that the proper endianess is set so
- *    that the bytes are transmitted in the right order for a smp request frame.
- * @sci_req: This parameter specifies the smp request object being
- *    constructed.
- *
- */
-static void
-scu_smp_request_construct_task_context(struct scic_sds_request *sci_req,
-                                      ssize_t req_len)
+static enum sci_status
+scic_io_request_construct_smp(struct device *dev,
+                             struct scic_sds_request *sci_req,
+                             struct sas_task *task)
 {
-       dma_addr_t dma_addr;
+       struct scatterlist *sg = &task->smp_task.smp_req;
        struct scic_sds_remote_device *sci_dev;
-       struct scic_sds_port *sci_port;
        struct scu_task_context *task_context;
-       ssize_t word_cnt = sizeof(struct smp_req) / sizeof(u32);
+       struct scic_sds_port *sci_port;
+       struct smp_req *smp_req;
+       void *kaddr;
+       u8 req_len;
+       u32 cmd;
+
+       kaddr = kmap_atomic(sg_page(sg), KM_IRQ0);
+       smp_req = kaddr + sg->offset;
+       /*
+        * Look at the SMP requests' header fields; for certain SAS 1.x SMP
+        * functions under SAS 2.0, a zero request length really indicates
+        * a non-zero default length.
+        */
+       if (smp_req->req_len == 0) {
+               switch (smp_req->func) {
+               case SMP_DISCOVER:
+               case SMP_REPORT_PHY_ERR_LOG:
+               case SMP_REPORT_PHY_SATA:
+               case SMP_REPORT_ROUTE_INFO:
+                       smp_req->req_len = 2;
+                       break;
+               case SMP_CONF_ROUTE_INFO:
+               case SMP_PHY_CONTROL:
+               case SMP_PHY_TEST_FUNCTION:
+                       smp_req->req_len = 9;
+                       break;
+                       /* Default - zero is a valid default for 2.0. */
+               }
+       }
+       req_len = smp_req->req_len;
+       sci_swab32_cpy(smp_req, smp_req, sg->length / sizeof(u32));
+       cmd = *(u32 *) smp_req;
+       kunmap_atomic(kaddr, KM_IRQ0);
+
+       if (!dma_map_sg(dev, sg, 1, DMA_TO_DEVICE))
+               return SCI_FAILURE;
+
+       sci_req->protocol = SCIC_SMP_PROTOCOL;
 
        /* byte swap the smp request. */
-       sci_swab32_cpy(&sci_req->smp.cmd, &sci_req->smp.cmd,
-                      word_cnt);
 
-       task_context = scic_sds_request_get_task_context(sci_req);
+       task_context = sci_req->tc;
 
        sci_dev = scic_sds_request_get_device(sci_req);
        sci_port = scic_sds_request_get_port(sci_req);
@@ -3292,7 +3224,7 @@ scu_smp_request_construct_task_context(struct scic_sds_request *sci_req,
         * 18h ~ 30h, protocol specific
         * since commandIU has been build by framework at this point, we just
         * copy the frist DWord from command IU to this location. */
-       memcpy(&task_context->type.smp, &sci_req->smp.cmd, sizeof(u32));
+       memcpy(&task_context->type.smp, &cmd, sizeof(u32));
 
        /*
         * 40h
@@ -3301,79 +3233,22 @@ scu_smp_request_construct_task_context(struct scic_sds_request *sci_req,
         */
        task_context->task_phase = 0;
 
-       if (sci_req->was_tag_assigned_by_user) {
-               /*
-                * Build the task context now since we have already read
-                * the data
-                */
-               sci_req->post_context =
-                       (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC |
-                        (scic_sds_controller_get_protocol_engine_group(scic) <<
-                         SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) |
-                        (scic_sds_port_get_index(sci_port) <<
-                         SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) |
-                         ISCI_TAG_TCI(sci_req->io_tag));
-       } else {
-               /*
-                * Build the task context now since we have already read
-                * the data.
-                * I/O tag index is not assigned because we have to wait
-                * until we get a TCi.
-                */
-               sci_req->post_context =
-                       (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC |
-                        (scic_sds_controller_get_protocol_engine_group(scic) <<
-                         SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) |
-                        (scic_sds_port_get_index(sci_port) <<
-                         SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT));
-       }
-
+       sci_req->post_context = (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC |
+                                (scic_sds_controller_get_protocol_engine_group(scic) <<
+                                 SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) |
+                                (scic_sds_port_get_index(sci_port) <<
+                                 SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) |
+                                ISCI_TAG_TCI(sci_req->io_tag));
        /*
         * Copy the physical address for the command buffer to the SCU Task
         * Context command buffer should not contain command header.
         */
-       dma_addr = scic_io_request_get_dma_addr(sci_req,
-                                               ((char *) &sci_req->smp.cmd) +
-                                               sizeof(u32));
-
-       task_context->command_iu_upper = upper_32_bits(dma_addr);
-       task_context->command_iu_lower = lower_32_bits(dma_addr);
+       task_context->command_iu_upper = upper_32_bits(sg_dma_address(sg));
+       task_context->command_iu_lower = lower_32_bits(sg_dma_address(sg) + sizeof(u32));
 
        /* SMP response comes as UF, so no need to set response IU address. */
        task_context->response_iu_upper = 0;
        task_context->response_iu_lower = 0;
-}
-
-static enum sci_status
-scic_io_request_construct_smp(struct scic_sds_request *sci_req)
-{
-       struct smp_req *smp_req = &sci_req->smp.cmd;
-
-       sci_req->protocol = SCIC_SMP_PROTOCOL;
-
-       /*
-        * Look at the SMP requests' header fields; for certain SAS 1.x SMP
-        * functions under SAS 2.0, a zero request length really indicates
-        * a non-zero default length.
-        */
-       if (smp_req->req_len == 0) {
-               switch (smp_req->func) {
-               case SMP_DISCOVER:
-               case SMP_REPORT_PHY_ERR_LOG:
-               case SMP_REPORT_PHY_SATA:
-               case SMP_REPORT_ROUTE_INFO:
-                       smp_req->req_len = 2;
-                       break;
-               case SMP_CONF_ROUTE_INFO:
-               case SMP_PHY_CONTROL:
-               case SMP_PHY_TEST_FUNCTION:
-                       smp_req->req_len = 9;
-                       break;
-                       /* Default - zero is a valid default for 2.0. */
-               }
-       }
-
-       scu_smp_request_construct_task_context(sci_req, smp_req->req_len);
 
        sci_change_state(&sci_req->sm, SCI_REQ_CONSTRUCTED);
 
@@ -3389,24 +3264,12 @@ scic_io_request_construct_smp(struct scic_sds_request *sci_req)
  */
 static enum sci_status isci_smp_request_build(struct isci_request *ireq)
 {
-       enum sci_status status = SCI_FAILURE;
        struct sas_task *task = isci_request_access_task(ireq);
+       struct device *dev = &ireq->isci_host->pdev->dev;
        struct scic_sds_request *sci_req = &ireq->sci;
+       enum sci_status status = SCI_FAILURE;
 
-       dev_dbg(&ireq->isci_host->pdev->dev,
-               "%s: request = %p\n", __func__, ireq);
-
-       dev_dbg(&ireq->isci_host->pdev->dev,
-               "%s: smp_req len = %d\n",
-               __func__,
-               task->smp_task.smp_req.length);
-
-       /* copy the smp_command to the address; */
-       sg_copy_to_buffer(&task->smp_task.smp_req, 1,
-                         &sci_req->smp.cmd,
-                         sizeof(struct smp_req));
-
-       status = scic_io_request_construct_smp(sci_req);
+       status = scic_io_request_construct_smp(dev, sci_req, task);
        if (status != SCI_SUCCESS)
                dev_warn(&ireq->isci_host->pdev->dev,
                         "%s: failed with status = %d\n",
@@ -3426,10 +3289,10 @@ static enum sci_status isci_smp_request_build(struct isci_request *ireq)
  *
  * SCI_SUCCESS on successfull completion, or specific failure code.
  */
-static enum sci_status isci_io_request_build(
-       struct isci_host *isci_host,
-       struct isci_request *request,
-       struct isci_remote_device *isci_device)
+static enum sci_status isci_io_request_build(struct isci_host *isci_host,
+                                            struct isci_request *request,
+                                            struct isci_remote_device *isci_device,
+                                            u16 tag)
 {
        enum sci_status status = SCI_SUCCESS;
        struct sas_task *task = isci_request_access_task(request);
@@ -3466,8 +3329,7 @@ static enum sci_status isci_io_request_build(
         * we will let the core allocate the IO tag.
         */
        status = scic_io_request_construct(&isci_host->sci, sci_device,
-                                          SCI_CONTROLLER_INVALID_IO_TAG,
-                                          &request->sci);
+                                          tag, &request->sci);
 
        if (status != SCI_SUCCESS) {
                dev_warn(&isci_host->pdev->dev,
@@ -3515,12 +3377,8 @@ static struct isci_request *isci_request_alloc_core(struct isci_host *ihost,
        ireq->request_daddr = handle;
        ireq->isci_host = ihost;
        ireq->io_request_completion = NULL;
-       ireq->terminated = false;
-
+       ireq->flags = 0;
        ireq->num_sg_entries = 0;
-
-       ireq->complete_in_target = false;
-
        INIT_LIST_HEAD(&ireq->completed_node);
        INIT_LIST_HEAD(&ireq->dev_node);
 
@@ -3559,7 +3417,7 @@ struct isci_request *isci_request_alloc_tmf(struct isci_host *ihost,
 }
 
 int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *idev,
-                        struct sas_task *task, gfp_t gfp_flags)
+                        struct sas_task *task, u16 tag, gfp_t gfp_flags)
 {
        enum sci_status status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
        struct isci_request *ireq;
@@ -3571,7 +3429,7 @@ int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *ide
        if (!ireq)
                goto out;
 
-       status = isci_io_request_build(ihost, ireq, idev);
+       status = isci_io_request_build(ihost, ireq, idev, tag);
        if (status != SCI_SUCCESS) {
                dev_warn(&ihost->pdev->dev,
                         "%s: request_construct failed - status = 0x%x\n",
@@ -3582,9 +3440,28 @@ int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *ide
 
        spin_lock_irqsave(&ihost->scic_lock, flags);
 
-       /* send the request, let the core assign the IO TAG.    */
-       status = scic_controller_start_io(&ihost->sci, &idev->sci, &ireq->sci,
-                                         SCI_CONTROLLER_INVALID_IO_TAG);
+       if (test_bit(IDEV_IO_NCQERROR, &idev->flags)) {
+
+               if (isci_task_is_ncq_recovery(task)) {
+
+                       /* The device is in an NCQ recovery state.  Issue the
+                        * request on the task side.  Note that it will
+                        * complete on the I/O request side because the
+                        * request was built that way (ie.
+                        * ireq->is_task_management_request is false).
+                        */
+                       status = scic_controller_start_task(&ihost->sci,
+                                                           &idev->sci,
+                                                           &ireq->sci);
+               } else {
+                       status = SCI_FAILURE;
+               }
+       } else {
+               /* send the request, let the core assign the IO TAG.    */
+               status = scic_controller_start_io(&ihost->sci, &idev->sci,
+                                                 &ireq->sci);
+       }
+
        if (status != SCI_SUCCESS &&
            status != SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) {
                dev_warn(&ihost->pdev->dev,
@@ -3613,7 +3490,7 @@ int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *ide
                 * hardware, so clear the request handle
                 * here so no terminations will be done.
                 */
-               ireq->terminated = true;
+               set_bit(IREQ_TERMINATED, &ireq->flags);
                isci_request_change_state(ireq, completed);
        }
        spin_unlock_irqrestore(&ihost->scic_lock, flags);
@@ -3621,23 +3498,23 @@ int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *ide
        if (status ==
            SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) {
                /* Signal libsas that we need the SCSI error
-               * handler thread to work on this I/O and that
-               * we want a device reset.
-               */
+                * handler thread to work on this I/O and that
+                * we want a device reset.
+                */
                spin_lock_irqsave(&task->task_state_lock, flags);
                task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
                spin_unlock_irqrestore(&task->task_state_lock, flags);
 
                /* Cause this task to be scheduled in the SCSI error
-               * handler thread.
-               */
+                * handler thread.
+                */
                isci_execpath_callback(ihost, task,
                                       sas_task_abort);
 
                /* Change the status, since we are holding
-               * the I/O until it is managed by the SCSI
-               * error handler.
-               */
+                * the I/O until it is managed by the SCSI
+                * error handler.
+                */
                status = SCI_SUCCESS;
        }