summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci/request.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/isci/request.c')
-rw-r--r--drivers/scsi/isci/request.c185
1 files changed, 164 insertions, 21 deletions
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 48e2dac7252..5f516811055 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -656,7 +656,7 @@ enum sci_status scic_sds_io_request_frame_handler(
* @sci_req: This parameter specifies the request object for which to copy
* the response data.
*/
-void scic_sds_io_request_copy_response(struct scic_sds_request *sci_req)
+static void scic_sds_io_request_copy_response(struct scic_sds_request *sci_req)
{
void *resp_buf;
u32 len;
@@ -978,7 +978,6 @@ scic_sds_io_request_tc_completion(struct scic_sds_request *request, u32 completi
sci_base_state_machine_get_state(&request->state_machine));
return SCI_FAILURE_INVALID_STATE;
-
}
/*
@@ -1151,9 +1150,119 @@ static enum sci_status scic_sds_request_aborting_state_frame_handler(
return SCI_SUCCESS;
}
+/**
+ * This method processes the completions transport layer (TL) status to
+ * determine if the RAW task management frame was sent successfully. If the
+ * raw frame was sent successfully, then the state for the task request
+ * transitions to waiting for a response frame.
+ * @sci_req: This parameter specifies the request for which the TC
+ * completion was received.
+ * @completion_code: This parameter indicates the completion status information
+ * for the TC.
+ *
+ * Indicate if the tc completion handler was successful. SCI_SUCCESS currently
+ * this method always returns success.
+ */
+static enum sci_status scic_sds_ssp_task_request_await_tc_completion_tc_completion_handler(
+ struct scic_sds_request *sci_req,
+ u32 completion_code)
+{
+ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
+ scic_sds_request_set_status(sci_req, SCU_TASK_DONE_GOOD,
+ SCI_SUCCESS);
+
+ sci_base_state_machine_change_state(&sci_req->state_machine,
+ SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE);
+ break;
+
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_ACK_NAK_TO):
+ /*
+ * Currently, the decision is to simply allow the task request to
+ * timeout if the task IU wasn't received successfully.
+ * There is a potential for receiving multiple task responses if we
+ * decide to send the task IU again. */
+ dev_warn(scic_to_dev(sci_req->owning_controller),
+ "%s: TaskRequest:0x%p CompletionCode:%x - "
+ "ACK/NAK timeout\n",
+ __func__,
+ sci_req,
+ completion_code);
+
+ sci_base_state_machine_change_state(&sci_req->state_machine,
+ SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE);
+ break;
+
+ default:
+ /*
+ * All other completion status cause the IO to be complete. If a NAK
+ * was received, then it is up to the user to retry the request. */
+ scic_sds_request_set_status(
+ sci_req,
+ SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
+ );
+
+ sci_base_state_machine_change_state(&sci_req->state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED);
+ break;
+ }
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method is responsible for processing a terminate/abort request for this
+ * TC while the request is waiting for the task management response
+ * unsolicited frame.
+ * @sci_req: This parameter specifies the request for which the
+ * termination was requested.
+ *
+ * This method returns an indication as to whether the abort request was
+ * successfully handled. need to update to ensure the received UF doesn't cause
+ * damage to subsequent requests (i.e. put the extended tag in a holding
+ * pattern for this particular device).
+ */
+static enum sci_status scic_sds_ssp_task_request_await_tc_response_abort_handler(
+ struct scic_sds_request *request)
+{
+ sci_base_state_machine_change_state(&request->state_machine,
+ SCI_BASE_REQUEST_STATE_ABORTING);
+ sci_base_state_machine_change_state(&request->state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED);
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method processes an unsolicited frame while the task mgmt request is
+ * waiting for a response frame. It will copy the response data, release
+ * the unsolicited frame, and transition the request to the
+ * SCI_BASE_REQUEST_STATE_COMPLETED state.
+ * @sci_req: This parameter specifies the request for which the
+ * unsolicited frame was received.
+ * @frame_index: This parameter indicates the unsolicited frame index that
+ * should contain the response.
+ *
+ * This method returns an indication of whether the TC response frame was
+ * handled successfully or not. SCI_SUCCESS Currently this value is always
+ * returned and indicates successful processing of the TC response. Should
+ * probably update to check frame type and make sure it is a response frame.
+ */
+static enum sci_status scic_sds_ssp_task_request_await_tc_response_frame_handler(
+ struct scic_sds_request *request,
+ u32 frame_index)
+{
+ scic_sds_io_request_copy_response(request);
+
+ sci_base_state_machine_change_state(&request->state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED);
+ scic_sds_controller_release_frame(request->owning_controller,
+ frame_index);
+ return SCI_SUCCESS;
+}
+
static const struct scic_sds_io_request_state_handler scic_sds_request_state_handler_table[] = {
- [SCI_BASE_REQUEST_STATE_INITIAL] = {
- },
+ [SCI_BASE_REQUEST_STATE_INITIAL] = { },
[SCI_BASE_REQUEST_STATE_CONSTRUCTED] = {
.start_handler = scic_sds_request_constructed_state_start_handler,
.abort_handler = scic_sds_request_constructed_state_abort_handler,
@@ -1163,6 +1272,14 @@ static const struct scic_sds_io_request_state_handler scic_sds_request_state_han
.tc_completion_handler = scic_sds_request_started_state_tc_completion_handler,
.frame_handler = scic_sds_request_started_state_frame_handler,
},
+ [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION] = {
+ .abort_handler = scic_sds_request_started_state_abort_handler,
+ .tc_completion_handler = scic_sds_ssp_task_request_await_tc_completion_tc_completion_handler,
+ },
+ [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE] = {
+ .abort_handler = scic_sds_ssp_task_request_await_tc_response_abort_handler,
+ .frame_handler = scic_sds_ssp_task_request_await_tc_response_frame_handler,
+ },
[SCI_BASE_REQUEST_STATE_COMPLETED] = {
.complete_handler = scic_sds_request_completed_state_complete_handler,
},
@@ -1171,8 +1288,7 @@ static const struct scic_sds_io_request_state_handler scic_sds_request_state_han
.tc_completion_handler = scic_sds_request_aborting_state_tc_completion_handler,
.frame_handler = scic_sds_request_aborting_state_frame_handler,
},
- [SCI_BASE_REQUEST_STATE_FINAL] = {
- },
+ [SCI_BASE_REQUEST_STATE_FINAL] = { },
};
@@ -1919,6 +2035,9 @@ static void scic_sds_request_constructed_state_enter(void *object)
static void scic_sds_request_started_state_enter(void *object)
{
struct scic_sds_request *sci_req = object;
+ struct sci_base_state_machine *sm = &sci_req->state_machine;
+ struct isci_request *ireq = sci_req_to_ireq(sci_req);
+ struct domain_device *dev = sci_dev_to_domain(sci_req->target_device);
SET_STATE_HANDLER(
sci_req,
@@ -1926,9 +2045,13 @@ static void scic_sds_request_started_state_enter(void *object)
SCI_BASE_REQUEST_STATE_STARTED
);
- /*
- * Most of the request state machines have a started substate machine so
- * start its execution on the entry to the started state. */
+ if (ireq->ttype == tmf_task && dev->dev_type == SAS_END_DEV)
+ sci_base_state_machine_change_state(sm,
+ SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION);
+
+ /* Most of the request state machines have a started substate machine so
+ * start its execution on the entry to the started state.
+ */
if (sci_req->has_started_substate_machine == true)
sci_base_state_machine_start(&sci_req->started_substate_machine);
}
@@ -2026,6 +2149,30 @@ static void scic_sds_request_final_state_enter(void *object)
);
}
+static void scic_sds_io_request_started_task_mgmt_await_tc_completion_substate_enter(
+ void *object)
+{
+ struct scic_sds_request *sci_req = object;
+
+ SET_STATE_HANDLER(
+ sci_req,
+ scic_sds_request_state_handler_table,
+ SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION
+ );
+}
+
+static void scic_sds_io_request_started_task_mgmt_await_task_response_substate_enter(
+ void *object)
+{
+ struct scic_sds_request *sci_req = object;
+
+ SET_STATE_HANDLER(
+ sci_req,
+ scic_sds_request_state_handler_table,
+ SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE
+ );
+}
+
static const struct sci_base_state scic_sds_request_state_table[] = {
[SCI_BASE_REQUEST_STATE_INITIAL] = {
.enter_state = scic_sds_request_initial_state_enter,
@@ -2037,6 +2184,12 @@ static const struct sci_base_state scic_sds_request_state_table[] = {
.enter_state = scic_sds_request_started_state_enter,
.exit_state = scic_sds_request_started_state_exit
},
+ [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION] = {
+ .enter_state = scic_sds_io_request_started_task_mgmt_await_tc_completion_substate_enter,
+ },
+ [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE] = {
+ .enter_state = scic_sds_io_request_started_task_mgmt_await_task_response_substate_enter,
+ },
[SCI_BASE_REQUEST_STATE_COMPLETED] = {
.enter_state = scic_sds_request_completed_state_enter,
},
@@ -2126,19 +2279,9 @@ enum sci_status scic_task_request_construct(struct scic_sds_controller *scic,
/* Build the common part of the request */
scic_sds_general_request_construct(scic, sci_dev, io_tag, sci_req);
- if (dev->dev_type == SAS_END_DEV) {
+ if (dev->dev_type == SAS_END_DEV)
scic_sds_ssp_task_request_assign_buffers(sci_req);
-
- sci_req->has_started_substate_machine = true;
-
- /* Construct the started sub-state machine. */
- sci_base_state_machine_construct(
- &sci_req->started_substate_machine,
- sci_req,
- scic_sds_io_request_started_task_mgmt_substate_table,
- SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION
- );
- } else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP))
+ else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP))
scic_sds_stp_request_assign_buffers(sci_req);
else
status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;