#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;
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);
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,
/* 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
* @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);
* 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);
/* 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
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);
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;
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;
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);
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),
/* 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;
}
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 "
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) {
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
"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);
* @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
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;
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 */
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) {
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,
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 {
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;
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;
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;
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;
*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;
}
*
* 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
* 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)
* 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
/* 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;
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;
/* 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
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:
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;
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;
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,
* 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)
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
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)
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;
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");
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
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;
}
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;
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);
* 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
*/
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);
*/
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",
*
* 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);
* 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,
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);
}
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;
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",
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,
* 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);
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;
}