X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Fscsi%2Fisci%2Frequest.c;h=27376ba2248380563a748c733e3b6102d567003d;hb=38d8879baeb61b6946052739e7c03fa79b3a57f0;hp=ebe160c83f91b44af9a5c10b793be2ed9a38cd0a;hpb=ff60639dc9a461883db9192d2da0674a00339f12;p=profile%2Fivi%2Fkernel-adaptation-intel-automotive.git diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index ebe160c..27376ba 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -61,42 +61,50 @@ #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; }