if (copy_rx_frame) {
sci_request_build_sgl(ireq);
stp_req->sgl.index = 0;
} else { /* The user does not want the data copied to the SGL buffer location */
stp_req->sgl.index = -1;
}
/* To simplify the implementation we take advantage of the *silicon'spartialaccelerationofatapiprotocol(dmadata *transfers),sowepromoteallcommandstodmaprotocol.This *breakscompatibilitywithATA_HORKAGE_ATAPI_MOD16_DMAdrives.
*/
h2d_fis->features |= ATAPI_PKT_DMA;
scu_stp_raw_request_construct_task_context(ireq);
task = isci_request_access_task(ireq); if (task->data_dir == DMA_NONE)
task->total_xfer_len = 0;
/* clear the response so we can detect arrivial of an *unsolicitedh2dfis
*/
ireq->stp.rsp.fis_type = 0;
}
/* check for management protocols */ if (test_bit(IREQ_TMF, &ireq->flags)) { struct isci_tmf *tmf = isci_request_access_tmf(ireq);
dev_err(&ireq->owning_controller->pdev->dev, "%s: Request 0x%p received un-handled SAT " "management protocol 0x%x.\n",
__func__, ireq, tmf->tmf_code);
return SCI_FAILURE;
}
if (!sas_protocol_ata(task->task_proto)) {
dev_err(&ireq->owning_controller->pdev->dev, "%s: Non-ATA protocol in SATA path: 0x%x\n",
__func__,
task->task_proto); return SCI_FAILURE;
state = ireq->sm.current_state_id; if (state != SCI_REQ_CONSTRUCTED) {
dev_warn(&ihost->pdev->dev, "%s: SCIC IO Request requested to start while in wrong " "state %d\n", __func__, state); return SCI_FAILURE_INVALID_STATE;
}
tc->task_index = ISCI_TAG_TCI(ireq->io_tag);
switch (tc->protocol_type) { case SCU_TASK_CONTEXT_PROTOCOL_SMP: case SCU_TASK_CONTEXT_PROTOCOL_SSP: /* SSP/SMP Frame */
tc->type.ssp.tag = ireq->io_tag;
tc->type.ssp.target_port_transfer_tag = 0xFFFF; break;
case SCU_TASK_CONTEXT_PROTOCOL_STP: /* STP/SATA Frame *tc->type.stp.ncq_tag=ireq->ncq_tag;
*/ break;
case SCU_TASK_CONTEXT_PROTOCOL_NONE: /* / @todo When do we set no protocol type? */ break;
default: /* This should never happen since we build the IO
* requests */ break;
}
/* Add to the post_context the io tag value */
ireq->post_context |= ISCI_TAG_TCI(ireq->io_tag);
/* Everything is good go ahead and change state */
sci_change_state(&ireq->sm, SCI_REQ_STARTED);
switch (state) { case SCI_REQ_CONSTRUCTED: /* Set to make sure no HW terminate posting is done: */
set_bit(IREQ_TC_ABORT_POSTED, &ireq->flags);
ireq->scu_status = SCU_TASK_DONE_TASK_ABORT;
ireq->sci_status = SCI_FAILURE_IO_TERMINATED;
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); return SCI_SUCCESS; case SCI_REQ_STARTED: case SCI_REQ_TASK_WAIT_TC_COMP: case SCI_REQ_SMP_WAIT_RESP: case SCI_REQ_SMP_WAIT_TC_COMP: case SCI_REQ_STP_UDMA_WAIT_TC_COMP: case SCI_REQ_STP_UDMA_WAIT_D2H: case SCI_REQ_STP_NON_DATA_WAIT_H2D: case SCI_REQ_STP_NON_DATA_WAIT_D2H: case SCI_REQ_STP_PIO_WAIT_H2D: case SCI_REQ_STP_PIO_WAIT_FRAME: case SCI_REQ_STP_PIO_DATA_IN: case SCI_REQ_STP_PIO_DATA_OUT: case SCI_REQ_ATAPI_WAIT_H2D: case SCI_REQ_ATAPI_WAIT_PIO_SETUP: case SCI_REQ_ATAPI_WAIT_D2H: case SCI_REQ_ATAPI_WAIT_TC_COMP: /* Fall through and change state to ABORTING... */ case SCI_REQ_TASK_WAIT_TC_RESP: /* The task frame was already confirmed to have been *sentbytheSCUHW.Sincethestatemachineis *nowonlywaitingforthetaskresponseitself, *aborttherequestandcompleteitimmediately *anddon'twaitforthetaskresponse.
*/
sci_change_state(&ireq->sm, SCI_REQ_ABORTING);
fallthrough; /* and handle like ABORTING */ case SCI_REQ_ABORTING: if (!isci_remote_device_is_safe_to_abort(ireq->target_device))
set_bit(IREQ_PENDING_ABORT, &ireq->flags); else
clear_bit(IREQ_PENDING_ABORT, &ireq->flags); /* If the request is only waiting on the remote device *suspension,returnSUCCESSsothecallerwillwaittoo.
*/ return SCI_SUCCESS; case SCI_REQ_COMPLETED: default:
dev_warn(&ireq->owning_controller->pdev->dev, "%s: SCIC IO Request requested to abort while in wrong " "state %d\n", __func__, ireq->sm.current_state_id); break;
}
state = ireq->sm.current_state_id; if (WARN_ONCE(state != SCI_REQ_COMPLETED, "isci: request completion from wrong state (%s)\n",
req_state_name(state))) return SCI_FAILURE_INVALID_STATE;
if (ireq->saved_rx_frame_index != SCU_INVALID_FRAME_INDEX)
sci_controller_release_frame(ihost,
ireq->saved_rx_frame_index);
/* XXX can we just stop the machine and remove the 'final' state? */
sci_change_state(&ireq->sm, SCI_REQ_FINAL); return SCI_SUCCESS;
}
if (state != SCI_REQ_STP_PIO_DATA_IN) {
dev_warn(&ihost->pdev->dev, "%s: (%x) in wrong state %s\n",
__func__, event_code, req_state_name(state));
return SCI_FAILURE_INVALID_STATE;
}
switch (scu_get_event_specifier(event_code)) { case SCU_TASK_DONE_CRC_ERR << SCU_EVENT_SPECIFIC_CODE_SHIFT: /* We are waiting for data and the SCU has R_ERR the data frame. *GobacktowaitingfortheD2HRegisterFIS
*/
sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_WAIT_FRAME); return SCI_SUCCESS; default:
dev_err(&ihost->pdev->dev, "%s: pio request unexpected event %#x\n",
__func__, event_code);
/* TODO Should we fail the PIO request when we get an *unexpectedevent?
*/ return SCI_FAILURE;
}
}
/* TODO: Any SDMA return code of other than 0 is bad decode 0x003C0000 *todetermineSDMAstatus
*/ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
ireq->scu_status = SCU_TASK_DONE_GOOD;
ireq->sci_status = SCI_SUCCESS; break; case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_EARLY_RESP): { /* There are times when the SCU hardware will return an early *responsebecausetheiorequestspecifiedmoredatathanis *returnedbythetargetdevice(modepages,inquirydata, *etc.).Wemustchecktheresponsestatstoseeifthisis *trulyafailedrequestoragoodrequestthatjustgot *completedearly.
*/ struct ssp_response_iu *resp = &ireq->ssp.rsp;
ssize_t word_cnt = SSP_RESP_IU_MAX_SIZE / sizeof(u32);
case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_RESP_LEN_ERR): /* TODO With TASK_DONE_RESP_LEN_ERR is the response frame *guaranteedtobereceivedbeforethiscompletionstatusis *posted?
*/
resp_iu = &ireq->ssp.rsp;
datapres = resp_iu->datapres;
if (datapres == SAS_DATAPRES_RESPONSE_DATA ||
datapres == SAS_DATAPRES_SENSE_DATA) {
ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
} else {
ireq->scu_status = SCU_TASK_DONE_GOOD;
ireq->sci_status = SCI_SUCCESS;
} break; /* only stp device gets suspended. */ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_ACK_NAK_TO): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_PERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_NAK_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_DATA_LEN_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_ABORT_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_XR_WD_LEN): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_MAX_PLD_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_RESP): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_SDBFIS): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDB_ERR): if (ireq->protocol == SAS_PROTOCOL_STP) {
ireq->scu_status = SCU_GET_COMPLETION_TL_STATUS(completion_code) >>
SCU_COMPLETION_TL_STATUS_SHIFT;
ireq->sci_status = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED;
} else {
ireq->scu_status = SCU_GET_COMPLETION_TL_STATUS(completion_code) >>
SCU_COMPLETION_TL_STATUS_SHIFT;
ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
} break;
/* both stp/ssp device gets suspended */ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LF_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_WRONG_DESTINATION): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_BAD_DESTINATION): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_ZONE_VIOLATION): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED):
ireq->scu_status = SCU_GET_COMPLETION_TL_STATUS(completion_code) >>
SCU_COMPLETION_TL_STATUS_SHIFT;
ireq->sci_status = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED; break;
/* neither ssp nor stp gets suspended. */ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_NAK_CMD_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_XR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_XR_IU_LEN_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDMA_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_OFFSET_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_EXCESS_DATA): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_DATA): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_OPEN_FAIL): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_VIIT_ENTRY_NV): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_IIT_ENTRY_NV): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_RNCNV_OUTBOUND): default:
ireq->scu_status = SCU_GET_COMPLETION_TL_STATUS(completion_code) >>
SCU_COMPLETION_TL_STATUS_SHIFT;
ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; break;
}
staticenum sci_status
smp_request_await_response_tc_event(struct isci_request *ireq,
u32 completion_code)
{ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): /* In the AWAIT RESPONSE state, any TC completion is *unexpected.butiftheTChassuccessstatus,we *completetheIOanyway.
*/
ireq->scu_status = SCU_TASK_DONE_GOOD;
ireq->sci_status = SCI_SUCCESS;
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); break; case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR): /* These status has been seen in a specific LSI *expander,whichsometimesisnotabletosendsmp *responsewithin2ms.Thiscausesourhardwarebreak *theconnectionandsetTCcompletionwithoneof *theseSMP_XXX_XX_ERRstatus.Forthesetypeoferror, *weaskihostusertoretrytherequest.
*/
ireq->scu_status = SCU_TASK_DONE_SMP_RESP_TO_ERR;
ireq->sci_status = SCI_FAILURE_RETRY_REQUIRED;
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); break; default: /* All other completion status cause the IO to be complete. If a NAK *wasreceived,thenitisuptotheusertoretrytherequest
*/
ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); break;
}
return SCI_SUCCESS;
}
staticenum sci_status
smp_request_await_tc_event(struct isci_request *ireq,
u32 completion_code)
{ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
ireq->scu_status = SCU_TASK_DONE_GOOD;
ireq->sci_status = SCI_SUCCESS;
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); break; default: /* All other completion status cause the IO to be *complete.IfaNAKwasreceived,thenitisupto *theusertoretrytherequest.
*/
ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); break;
}
default: /* All other completion status cause the IO to be *complete.IfaNAKwasreceived,thenitisupto *theusertoretrytherequest.
*/
ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); break;
}
return SCI_SUCCESS;
}
#define SCU_MAX_FRAME_BUFFER_SIZE 0x400 /* 1K is the maximum SCU frame data payload */
/* Recycle the TC and reconstruct it for sending out DATA FIS containing *forthedatafromcurrent_sgl+offsetfortheinputlength
*/
sgl_pair = to_sgl_element_pair(ireq, stp_req->sgl.index); if (stp_req->sgl.set == SCU_SGL_ELEMENT_PAIR_A)
current_sgl = &sgl_pair->A; else
current_sgl = &sgl_pair->B;
if (stp_req->sgl.set == SCU_SGL_ELEMENT_PAIR_A) {
sgl = &sgl_pair->A;
len = sgl_pair->A.length - offset;
} else {
sgl = &sgl_pair->B;
len = sgl_pair->B.length - offset;
}
if (stp_req->pio_len == 0) return SCI_SUCCESS;
if (stp_req->pio_len >= len) {
status = sci_stp_request_pio_data_out_trasmit_data_frame(ireq, len); if (status != SCI_SUCCESS) return status;
stp_req->pio_len -= len;
/* update the current sgl, offset and save for future */
sgl = pio_sgl_next(stp_req);
offset = 0;
} elseif (stp_req->pio_len < len) {
sci_stp_request_pio_data_out_trasmit_data_frame(ireq, stp_req->pio_len);
/* Sgl offset will be adjusted and saved for future */
offset += stp_req->pio_len;
sgl->address_lower += stp_req->pio_len;
stp_req->pio_len = 0;
}
/* *Ifthereislessthan1Kremaininginthetransferrequest
* copy just the data for the transfer */ if (stp_req->pio_len < SCU_MAX_FRAME_BUFFER_SIZE) {
status = sci_stp_request_pio_data_in_copy_data_buffer(
stp_req, data_buffer, stp_req->pio_len);
if (status == SCI_SUCCESS)
stp_req->pio_len = 0;
} else { /* We are transfering the whole frame so copy */
status = sci_stp_request_pio_data_in_copy_data_buffer(
stp_req, data_buffer, SCU_MAX_FRAME_BUFFER_SIZE);
if (status == SCI_SUCCESS)
stp_req->pio_len -= SCU_MAX_FRAME_BUFFER_SIZE;
}
default: /* All other completion status cause the IO to be *complete.IfaNAKwasreceived,thenitisupto *theusertoretrytherequest.
*/
ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); break;
}
switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): /* Transmit data */ if (stp_req->pio_len != 0) {
status = sci_stp_request_pio_data_out_transmit_data(ireq); if (status == SCI_SUCCESS) { if (stp_req->pio_len == 0)
all_frames_transferred = true;
}
} elseif (stp_req->pio_len == 0) { /* *thiswillhappenifthealldataiswrittenatthe *firsttimeafterthepiosetupfisisreceived
*/
all_frames_transferred = true;
}
/* all data transferred. */ if (all_frames_transferred) { /* *ChangethestatetoSCI_REQ_STP_PIO_DATA_IN
* and wait for PIO_SETUP fis / or D2H REg fis. */
sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_WAIT_FRAME);
} break;
status = process_unsolicited_fis(ireq, frame_index);
if (status == SCI_SUCCESS) { if (ireq->stp.rsp.status & ATA_ERR)
status = SCI_FAILURE_IO_RESPONSE_VALID;
} else {
status = SCI_FAILURE_IO_RESPONSE_VALID;
}
/* fill in the SCU Task Context for a DATA fis containing CDB in Raw Frame *type.TheTCforpreviousPacketfiswasalreadythere,weonlyneedto *changetheH2Dfiscontent.
*/
memset(&ireq->stp.cmd, 0, sizeof(struct host_to_dev_fis));
memcpy(((u8 *)&ireq->stp.cmd + sizeof(u32)), atapi_cdb, ATAPI_CDB_LEN);
memset(&(task_context->type.stp), 0, sizeof(struct stp_task_context));
task_context->type.stp.fis_type = FIS_DATA;
task_context->transfer_length_bytes = dev->cdb_len;
}
case SCI_REQ_STP_UDMA_WAIT_TC_COMP: return sci_stp_request_udma_general_frame_handler(ireq,
frame_index);
case SCI_REQ_STP_UDMA_WAIT_D2H: /* Use the general frame handler to copy the resposne data */
status = sci_stp_request_udma_general_frame_handler(ireq, frame_index);
case SCI_REQ_STP_NON_DATA_WAIT_D2H: { struct dev_to_host_fis *frame_header;
u32 *frame_buffer;
status = sci_unsolicited_frame_control_get_header(&ihost->uf_control,
frame_index,
(void **)&frame_header);
if (status != SCI_SUCCESS) {
dev_err(&ihost->pdev->dev, "%s: SCIC IO Request 0x%p could not get frame " "header for frame index %d, status %x\n",
__func__,
stp_req,
frame_index,
status);
return status;
}
switch (frame_header->fis_type) { case FIS_REGD2H:
sci_unsolicited_frame_control_get_buffer(&ihost->uf_control,
frame_index,
(void **)&frame_buffer);
status = sci_unsolicited_frame_control_get_header(&ihost->uf_control,
frame_index,
(void **)&frame_header);
if (status != SCI_SUCCESS) {
dev_err(&ihost->pdev->dev, "%s: SCIC IO Request 0x%p could not get frame " "header for frame index %d, status %x\n",
__func__, stp_req, frame_index, status); return status;
}
switch (frame_header->fis_type) { case FIS_PIO_SETUP: /* Get from the frame buffer the PIO Setup Data */
sci_unsolicited_frame_control_get_buffer(&ihost->uf_control,
frame_index,
(void **)&frame_buffer);
/* Get the data from the PIO Setup The SCU Hardware *returnsfirstwordintheframe_headerandtherest *ofthedataisintheframebuffersoweneedto *backuponedword
*/
/* transfer_count: first 16bits in the 4th dword */
stp_req->pio_len = frame_buffer[3] & 0xffff;
/* status: 4th byte in the 3rd dword */
stp_req->status = (frame_buffer[2] >> 24) & 0xff;
/* The next state is dependent on whether the *requestwasPIOData-inorDataout
*/ if (task->data_dir == DMA_FROM_DEVICE) {
sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_DATA_IN);
} elseif (task->data_dir == DMA_TO_DEVICE) { /* Transmit data */
status = sci_stp_request_pio_data_out_transmit_data(ireq); if (status != SCI_SUCCESS) break;
sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_DATA_OUT);
} break;
case FIS_SETDEVBITS:
sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_WAIT_FRAME); break;
case FIS_REGD2H: if (frame_header->status & ATA_BUSY) { /* *NowwhyisthedrivesendingaD2HRegister *FISwhenitisstillbusy?Donothingsince *wearestillintherightstate.
*/
dev_dbg(&ihost->pdev->dev, "%s: SCIC PIO Request 0x%p received " "D2H Register FIS with BSY status " "0x%x\n",
__func__,
stp_req,
frame_header->status); break;
}
default: /* FIXME: what do we do here? */ break;
}
/* Frame is decoded return it to the controller */
sci_controller_release_frame(ihost, frame_index);
return status;
}
case SCI_REQ_STP_PIO_DATA_IN: { struct dev_to_host_fis *frame_header; struct sata_fis_data *frame_buffer;
status = sci_unsolicited_frame_control_get_header(&ihost->uf_control,
frame_index,
(void **)&frame_header);
if (status != SCI_SUCCESS) {
dev_err(&ihost->pdev->dev, "%s: SCIC IO Request 0x%p could not get frame " "header for frame index %d, status %x\n",
__func__,
stp_req,
frame_index,
status); return status;
}
if (frame_header->fis_type != FIS_DATA) {
dev_err(&ihost->pdev->dev, "%s: SCIC PIO Request 0x%p received frame %d " "with fis type 0x%02x when expecting a data " "fis.\n",
__func__,
stp_req,
frame_index,
frame_header->fis_type);
status = sci_stp_request_pio_data_in_copy_data(stp_req,
(u8 *)frame_buffer);
/* Frame is decoded return it to the controller */
sci_controller_release_frame(ihost, frame_index);
}
/* Check for the end of the transfer, are there more *bytesremainingforthisdatatransfer
*/ if (status != SCI_SUCCESS || stp_req->pio_len != 0) return status;
staticenum sci_status stp_request_udma_await_tc_event(struct isci_request *ireq,
u32 completion_code)
{ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
ireq->scu_status = SCU_TASK_DONE_GOOD;
ireq->sci_status = SCI_SUCCESS;
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); break; case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_FIS): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR): /* We must check ther response buffer to see if the D2H *RegisterFISwasreceivedbeforewegottheTC *completion.
*/ if (ireq->stp.rsp.fis_type == FIS_REGD2H) {
sci_remote_device_suspend(ireq->target_device,
SCI_SW_SUSPEND_NORMAL);
ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
} else { /* If we have an error completion status for the *TCthenwecanexpectaD2HregisterFISfrom *thedevicesowemustchangestatetowait *forit
*/
sci_change_state(&ireq->sm, SCI_REQ_STP_UDMA_WAIT_D2H);
} break;
/* TODO Check to see if any of these completion status need to *waitforthedevicetohostregisterfis.
*/ /* TODO We can retry the command for SCU_TASK_DONE_CMD_LL_R_ERR *-thiscomesonlyforB0
*/ default: /* All other completion status cause the IO to be complete. */
ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); break;
}
return SCI_SUCCESS;
}
staticenum sci_status atapi_raw_completion(struct isci_request *ireq, u32 completion_code, enum sci_base_request_states next)
{ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
ireq->scu_status = SCU_TASK_DONE_GOOD;
ireq->sci_status = SCI_SUCCESS;
sci_change_state(&ireq->sm, next); break; default: /* All other completion status cause the IO to be complete. *IfaNAKwasreceived,thenitisuptotheusertoretry *therequest.
*/
ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
ireq->scu_status = SCU_TASK_DONE_GOOD;
ireq->sci_status = SCI_SUCCESS_IO_DONE_EARLY;
status = ireq->sci_status;
/* the hw will have suspended the rnc, so complete the *requestuponpendingresume
*/
sci_change_state(&idev->sm, SCI_STP_DEV_ATAPI_ERROR); break;
} case (SCU_TASK_DONE_EXCESS_DATA << SCU_COMPLETION_TL_STATUS_SHIFT): /* In this case, there is no UF coming after. *compeltetheIOnow.
*/
ireq->scu_status = SCU_TASK_DONE_GOOD;
ireq->sci_status = SCI_SUCCESS;
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); break;
default: if (d2h->fis_type == FIS_REGD2H) { /* UF received change the device state to ATAPI_ERROR */
status = ireq->sci_status;
sci_change_state(&idev->sm, SCI_STP_DEV_ATAPI_ERROR);
} else { /* If receiving any non-success TC status, no UF *receivedyet,thenanUFforthestatusfis *iscomingafter(XXX:suspectthisis *actuallyaprotocolerrororabuglikethe *DONE_UNEXP_FIScase)
*/
ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
staticint sci_request_smp_completion_status_is_tx_suspend( unsignedint completion_status)
{ switch (completion_status) { case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION: case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1: case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2: case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3: case SCU_TASK_OPEN_REJECT_BAD_DESTINATION: case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION: return1;
} return0;
}
staticint sci_request_smp_completion_status_is_tx_rx_suspend( unsignedint completion_status)
{ return0; /* There are no Tx/Rx SMP suspend conditions. */
}
staticint sci_request_ssp_completion_status_is_tx_suspend( unsignedint completion_status)
{ switch (completion_status) { case SCU_TASK_DONE_TX_RAW_CMD_ERR: case SCU_TASK_DONE_LF_ERR: case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION: case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1: case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2: case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3: case SCU_TASK_OPEN_REJECT_BAD_DESTINATION: case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION: case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY: case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED: case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED: return1;
} return0;
}
staticint sci_request_ssp_completion_status_is_tx_rx_suspend( unsignedint completion_status)
{ return0; /* There are no Tx/Rx SSP suspend conditions. */
}
staticint sci_request_stpsata_completion_status_is_tx_suspend( unsignedint completion_status)
{ switch (completion_status) { case SCU_TASK_DONE_TX_RAW_CMD_ERR: case SCU_TASK_DONE_LL_R_ERR: case SCU_TASK_DONE_LL_PERR: case SCU_TASK_DONE_REG_ERR: case SCU_TASK_DONE_SDB_ERR: case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION: case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1: case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2: case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3: case SCU_TASK_OPEN_REJECT_BAD_DESTINATION: case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION: case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY: case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED: case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED: return1;
} return0;
}
staticint sci_request_stpsata_completion_status_is_tx_rx_suspend( unsignedint completion_status)
{ switch (completion_status) { case SCU_TASK_DONE_LF_ERR: case SCU_TASK_DONE_LL_SY_TERM: case SCU_TASK_DONE_LL_LF_TERM: case SCU_TASK_DONE_BREAK_RCVD: case SCU_TASK_DONE_INV_FIS_LEN: case SCU_TASK_DONE_UNEXP_FIS: case SCU_TASK_DONE_UNEXP_SDBFIS: case SCU_TASK_DONE_MAX_PLD_ERR: return1;
} return0;
}
staticvoid sci_request_handle_suspending_completions( struct isci_request *ireq,
u32 completion_code)
{ int is_tx = 0; int is_tx_rx = 0;
switch (ireq->protocol) { case SAS_PROTOCOL_SMP:
is_tx = sci_request_smp_completion_status_is_tx_suspend(
completion_code);
is_tx_rx = sci_request_smp_completion_status_is_tx_rx_suspend(
completion_code); break; case SAS_PROTOCOL_SSP:
is_tx = sci_request_ssp_completion_status_is_tx_suspend(
completion_code);
is_tx_rx = sci_request_ssp_completion_status_is_tx_rx_suspend(
completion_code); break; case SAS_PROTOCOL_STP:
is_tx = sci_request_stpsata_completion_status_is_tx_suspend(
completion_code);
is_tx_rx =
sci_request_stpsata_completion_status_is_tx_rx_suspend(
completion_code); break; default:
dev_warn(&ireq->isci_host->pdev->dev, "%s: request %p has no valid protocol\n",
__func__, ireq); break;
} if (is_tx || is_tx_rx) {
BUG_ON(is_tx && is_tx_rx);
/* Decode those completions that signal upcoming suspension events. */
sci_request_handle_suspending_completions(
ireq, SCU_GET_COMPLETION_TL_STATUS(completion_code));
switch (state) { case SCI_REQ_STARTED: return request_started_state_tc_event(ireq, completion_code);
case SCI_REQ_TASK_WAIT_TC_COMP: return ssp_task_request_await_tc_event(ireq,
completion_code);
case SCI_REQ_SMP_WAIT_RESP: return smp_request_await_response_tc_event(ireq,
completion_code);
case SCI_REQ_SMP_WAIT_TC_COMP: return smp_request_await_tc_event(ireq, completion_code);
case SCI_REQ_STP_UDMA_WAIT_TC_COMP: return stp_request_udma_await_tc_event(ireq,
completion_code);
case SCI_REQ_STP_NON_DATA_WAIT_H2D: return stp_request_non_data_await_h2d_tc_event(ireq,
completion_code);
case SCI_REQ_STP_PIO_WAIT_H2D: return stp_request_pio_await_h2d_completion_tc_event(ireq,
completion_code);
case SCI_REQ_STP_PIO_DATA_OUT: return pio_data_out_tx_done_tc_event(ireq, completion_code);
case SCI_REQ_ABORTING: return request_aborting_state_tc_event(ireq,
completion_code);
case SCI_REQ_ATAPI_WAIT_H2D: return atapi_raw_completion(ireq, completion_code,
SCI_REQ_ATAPI_WAIT_PIO_SETUP);
case SCI_REQ_ATAPI_WAIT_TC_COMP: return atapi_raw_completion(ireq, completion_code,
SCI_REQ_ATAPI_WAIT_D2H);
case SCI_REQ_ATAPI_WAIT_D2H: return atapi_data_tc_completion_handler(ireq, completion_code);
default:
dev_warn(&ihost->pdev->dev, "%s: %x in wrong state %s\n",
__func__, completion_code, req_state_name(state)); return SCI_FAILURE_INVALID_STATE;
}
}
/* Decode the controller-specific errors; most *importantistorecognizethoseconditionsinwhich *thetargetmaystillhaveataskoutstandingthat *mustbeaborted. * *NotethatthereareSCUcompletioncodesbeing *namedinthedecodebelowforwhichSCIChasalready *doneworktohandletheminawayotherthanas *acontroller-specificcompletioncode;theseareleft *inthedecodebelowforcompletenesssake.
*/ switch (cstatus) { case SCU_TASK_DONE_DMASETUP_DIRERR: /* Also SCU_TASK_DONE_SMP_FRM_TYPE_ERR: */ case SCU_TASK_DONE_XFERCNT_ERR: /* Also SCU_TASK_DONE_SMP_UFI_ERR: */ if (task->task_proto == SAS_PROTOCOL_SMP) { /* SCU_TASK_DONE_SMP_UFI_ERR == Task Done. */
*response_ptr = SAS_TASK_COMPLETE;
/* See if the device has been/is being stopped. Note *thatweignorethequiescestate,sinceweare *concernedabouttheactualdevicestate.
*/ if (!idev)
*status_ptr = SAS_DEVICE_UNKNOWN; else
*status_ptr = SAS_ABORTED_TASK;
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
} else { /* Task in the target is not done. */
*response_ptr = SAS_TASK_UNDELIVERED;
if (!idev)
*status_ptr = SAS_DEVICE_UNKNOWN; else
*status_ptr = SAS_SAM_STAT_TASK_ABORTED;
case SCU_TASK_DONE_CRC_ERR: case SCU_TASK_DONE_NAK_CMD_ERR: case SCU_TASK_DONE_EXCESS_DATA: case SCU_TASK_DONE_UNEXP_FIS: /* Also SCU_TASK_DONE_UNEXP_RESP: */ case SCU_TASK_DONE_VIIT_ENTRY_NV: /* TODO - conditions? */ case SCU_TASK_DONE_IIT_ENTRY_NV: /* TODO - conditions? */ case SCU_TASK_DONE_RNCNV_OUTBOUND: /* TODO - conditions? */ /* These are conditions in which the target *hascompletedthetask,sothatnocleanup *isnecessary.
*/
*response_ptr = SAS_TASK_COMPLETE;
/* See if the device has been/is being stopped. Note *thatweignorethequiescestate,sinceweare *concernedabouttheactualdevicestate.
*/ if (!idev)
*status_ptr = SAS_DEVICE_UNKNOWN; else
*status_ptr = SAS_ABORTED_TASK;
/* Note that the only open reject completion codes seen here will be *abandon-classcodes;allothersareautomaticallyretriedintheSCU.
*/ case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION:
/* Note - the return of AB0 will change when *libsasimplementsdetectionofzoneviolations.
*/
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
SAS_OREJ_RESV_AB0); break;
case SCU_TASK_DONE_LL_R_ERR: /* Also SCU_TASK_DONE_ACK_NAK_TO: */ case SCU_TASK_DONE_LL_PERR: case SCU_TASK_DONE_LL_SY_TERM: /* Also SCU_TASK_DONE_NAK_ERR:*/ case SCU_TASK_DONE_LL_LF_TERM: /* Also SCU_TASK_DONE_DATA_LEN_ERR: */ case SCU_TASK_DONE_LL_ABORT_ERR: case SCU_TASK_DONE_SEQ_INV_TYPE: /* Also SCU_TASK_DONE_UNEXP_XR: */ case SCU_TASK_DONE_XR_IU_LEN_ERR: case SCU_TASK_DONE_INV_FIS_LEN: /* Also SCU_TASK_DONE_XR_WD_LEN: */ case SCU_TASK_DONE_SDMA_ERR: case SCU_TASK_DONE_OFFSET_ERR: case SCU_TASK_DONE_MAX_PLD_ERR: case SCU_TASK_DONE_LF_ERR: case SCU_TASK_DONE_SMP_RESP_TO_ERR: /* Escalate to dev reset? */ case SCU_TASK_DONE_SMP_LL_RX_ERR: case SCU_TASK_DONE_UNEXP_DATA: case SCU_TASK_DONE_UNEXP_SDBFIS: case SCU_TASK_DONE_REG_ERR: case SCU_TASK_DONE_SDB_ERR: case SCU_TASK_DONE_TASK_ABORT: default: /* Task in the target is not done. */
*response_ptr = SAS_TASK_UNDELIVERED;
*status_ptr = SAS_SAM_STAT_TASK_ABORTED;
/* use the task status set in the task struct by the *isci_request_process_response_iucall.
*/
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
response = task->task_status.resp;
status = task->task_status.stat; break;
case SCI_IO_SUCCESS: case SCI_IO_SUCCESS_IO_DONE_EARLY:
response = SAS_TASK_COMPLETE;
status = SAS_SAM_STAT_GOOD;
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
if (completion_status == SCI_IO_SUCCESS_IO_DONE_EARLY) {
/* This was an SSP / STP / SATA transfer. *Thereisapossibilitythatlessdatathan *themaximumwastransferred.
*/
u32 transferred_length = sci_req_tx_bytes(request);
/* The request was terminated explicitly. */
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
response = SAS_TASK_UNDELIVERED;
/* See if the device has been/is being stopped. Note *thatweignorethequiescestate,sinceweare *concernedabouttheactualdevicestate.
*/ if (!idev)
status = SAS_DEVICE_UNKNOWN; else
status = SAS_ABORTED_TASK; break;
case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED: /* This is a special case, in that the I/O completion *istellingusthatthedeviceneedsareset. *Inorderforthedeviceresetconditiontobe *noticed,theI/Ohastobehandledintheerror *handler.Settheresetflagandcausethe *SCSIerrorthreadtobescheduled.
*/
spin_lock_irqsave(&task->task_state_lock, task_flags);
task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
spin_unlock_irqrestore(&task->task_state_lock, task_flags);
/* Fail the I/O. */
response = SAS_TASK_UNDELIVERED;
status = SAS_SAM_STAT_TASK_ABORTED;
/* See if the device has been/is being stopped. Note *thatweignorethequiescestate,sinceweare *concernedabouttheactualdevicestate.
*/ if (!idev)
status = SAS_DEVICE_UNKNOWN; else
status = SAS_ABORTED_TASK;
/* need to swab it back in case the command buffer is re-used */
kaddr = kmap_atomic(sg_page(sg));
smp_req = kaddr + sg->offset;
sci_swab32_cpy(smp_req, smp_req, sg->length / sizeof(u32));
kunmap_atomic(kaddr); break;
} default: break;
}
if (test_bit(IREQ_COMPLETE_IN_TARGET, &request->flags)) { /* Normal notification (task_done) */
task->task_state_flags |= SAS_TASK_STATE_DONE;
task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
}
spin_unlock_irqrestore(&task->task_state_lock, task_flags);
/* complete the io request to the core. */
sci_controller_complete_io(ihost, request->target_device, request);
/* set terminated handle so it cannot be completed or *terminatedagain,andtocauseanycallsintoabort *tasktorecognizethealreadycompletedcase.
*/
set_bit(IREQ_TERMINATED, &request->flags);
/* Tell the SCI_USER that the IO request is complete */ if (!test_bit(IREQ_TMF, &ireq->flags))
isci_request_io_request_complete(ihost, ireq,
ireq->sci_status); else
isci_task_request_complete(ihost, ireq, ireq->sci_status);
}
/* Set the protocol indicator. */ if (dev_is_sata(dev))
ireq->protocol = SAS_PROTOCOL_STP; else
ireq->protocol = SAS_PROTOCOL_SSP;
} else
status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
/* *18h~30h,protocolspecific *sincecommandIUhasbeenbuildbyframeworkatthispoint,wejust
* copy the frist DWord from command IU to this location. */
memcpy(&task_context->type.smp, &cmd, sizeof(u32));
status = sci_io_request_construct_smp(dev, ireq, task); if (status != SCI_SUCCESS)
dev_dbg(&ireq->isci_host->pdev->dev, "%s: failed with status = %d\n",
__func__,
status);
switch (task->task_proto) { case SAS_PROTOCOL_SMP:
status = isci_smp_request_build(request); break; case SAS_PROTOCOL_SSP:
status = isci_request_ssp_request_construct(request); break; case SAS_PROTOCOL_SATA: case SAS_PROTOCOL_STP: case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
status = isci_request_stp_request_construct(request); break; default:
dev_dbg(&ihost->pdev->dev, "%s: unknown protocol\n", __func__); return SCI_FAILURE;
}
int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *idev, struct sas_task *task, struct isci_request *ireq)
{ enum sci_status status; unsignedlong flags; int ret = 0;
status = isci_io_request_build(ihost, ireq, idev); if (status != SCI_SUCCESS) {
dev_dbg(&ihost->pdev->dev, "%s: request_construct failed - status = 0x%x\n",
__func__,
status); return status;
}
spin_lock_irqsave(&ihost->scic_lock, flags);
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 *requestonthetaskside.Notethatitwill *completeontheI/Orequestsidebecausethe *requestwasbuiltthatway(ie. *ireq->is_task_management_requestisfalse).
*/
status = sci_controller_start_task(ihost,
idev,
ireq);
} else {
status = SCI_FAILURE;
}
} else { /* send the request, let the core assign the IO TAG. */
status = sci_controller_start_io(ihost, idev,
ireq);
}
if (status != SCI_SUCCESS &&
status != SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) {
dev_dbg(&ihost->pdev->dev, "%s: failed request start (0x%x)\n",
__func__, status);
spin_unlock_irqrestore(&ihost->scic_lock, flags); return status;
} /* Either I/O started OK, or the core has signaled that *thedeviceneedsatargetreset.
*/ if (status != SCI_SUCCESS) { /* The request did not really start in the *hardware,socleartherequesthandle *heresonoterminationswillbedone.
*/
set_bit(IREQ_TERMINATED, &ireq->flags);
}
spin_unlock_irqrestore(&ihost->scic_lock, flags);
if (status ==
SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) { /* Signal libsas that we need the SCSI error *handlerthreadtoworkonthisI/Oandthat *wewantadevicereset.
*/
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 *handlerthread.
*/
sas_task_abort(task);
/* Change the status, since we are holding *theI/OuntilitismanagedbytheSCSI *errorhandler.
*/
status = SCI_SUCCESS;
}
return ret;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.63 Sekunden
(vorverarbeitet am 2026-10-01)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.