/* Check for a change in the suspend count, or the RNC *beingdestroyed.
*/ return (localcount != idev->rnc.suspend_count)
|| sci_remote_node_context_is_being_destroyed(&idev->rnc);
}
switch (reason) { case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED:
set_bit(IDEV_IO_NCQERROR, &idev->flags);
/* Suspend the remote device so the I/O can be terminated. */
sci_remote_device_suspend(idev, SCI_SW_SUSPEND_NORMAL);
/* Kill all outstanding requests for the device. */
sci_remote_device_terminate_requests(idev);
fallthrough; /* into the default case */ default:
clear_bit(IDEV_IO_READY, &idev->flags); break;
}
}
/* called once the remote node context is ready to be freed. *Theremotedevicecannowreportthatitsstopoperationiscomplete.none
*/ staticvoid rnc_destruct_done(void *_dev)
{ struct isci_remote_device *idev = _dev;
switch (state) { case SCI_DEV_INITIAL: case SCI_DEV_FAILED: case SCI_DEV_FINAL: default:
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
__func__, dev_state_name(state)); return SCI_FAILURE_INVALID_STATE; case SCI_DEV_STOPPED: return SCI_SUCCESS; case SCI_DEV_STARTING: /* device not started so there had better be no requests */
BUG_ON(idev->started_request_count != 0);
sci_remote_node_context_destruct(&idev->rnc,
rnc_destruct_done, idev); /* Transition to the stopping state and wait for the *remotenodetocompletebeingpostedandinvalidated.
*/
sci_change_state(sm, SCI_DEV_STOPPING); return SCI_SUCCESS; case SCI_DEV_READY: case SCI_STP_DEV_IDLE: case SCI_STP_DEV_CMD: case SCI_STP_DEV_NCQ: case SCI_STP_DEV_NCQ_ERROR: case SCI_STP_DEV_AWAIT_RESET: case SCI_SMP_DEV_IDLE: case SCI_SMP_DEV_CMD:
sci_change_state(sm, SCI_DEV_STOPPING); if (idev->started_request_count == 0)
sci_remote_node_context_destruct(&idev->rnc,
rnc_destruct_done,
idev); else {
sci_remote_device_suspend(
idev, SCI_SW_SUSPEND_LINKHANG_DETECT);
sci_remote_device_terminate_requests(idev);
} return SCI_SUCCESS; case SCI_DEV_STOPPING: /* All requests should have been terminated, but if there is an *attempttostopadevicealreadyinthestoppingstate,then *tryagaintoterminate.
*/ return sci_remote_device_terminate_requests(idev); case SCI_DEV_RESETTING:
sci_change_state(sm, SCI_DEV_STOPPING); return SCI_SUCCESS;
}
}
switch (state) { case SCI_DEV_INITIAL: case SCI_DEV_STOPPED: case SCI_DEV_STARTING: case SCI_STP_DEV_IDLE: case SCI_SMP_DEV_IDLE: case SCI_DEV_FINAL: default:
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
__func__, dev_state_name(state)); /* Return the frame back to the controller */
sci_controller_release_frame(ihost, frame_index); return SCI_FAILURE_INVALID_STATE; case SCI_DEV_READY: case SCI_STP_DEV_NCQ_ERROR: case SCI_STP_DEV_AWAIT_RESET: case SCI_DEV_STOPPING: case SCI_DEV_FAILED: case SCI_DEV_RESETTING: { struct isci_request *ireq; struct ssp_frame_hdr hdr; void *frame_header;
ssize_t word_cnt;
status = sci_unsolicited_frame_control_get_header(&ihost->uf_control,
frame_index,
&frame_header); if (status != SCI_SUCCESS) return status;
ireq = sci_request_by_tag(ihost, be16_to_cpu(hdr.tag)); if (ireq && ireq->target_device == idev) { /* The IO request is now in charge of releasing the frame */
status = sci_io_request_frame_handler(ireq, frame_index);
} else { /* We could not map this tag to a valid IO *requestJusttosstheframeandcontinue
*/
sci_controller_release_frame(ihost, frame_index);
} break;
} case SCI_STP_DEV_NCQ: { struct dev_to_host_fis *hdr;
status = sci_unsolicited_frame_control_get_header(&ihost->uf_control,
frame_index,
(void **)&hdr); if (status != SCI_SUCCESS) return status;
/* TODO Check sactive and complete associated IO if any. */
sci_change_state(sm, SCI_STP_DEV_NCQ_ERROR);
} elseif (hdr->fis_type == FIS_REGD2H &&
(hdr->status & ATA_ERR)) { /* *SomedevicesreturnD2HFISwhenanNCQerrorisdetected. *TreatthislikeanSDBerrorFISreadyreason.
*/
idev->not_ready_reason = SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED;
sci_change_state(&idev->sm, SCI_STP_DEV_NCQ_ERROR);
} else
status = SCI_FAILURE;
sci_controller_release_frame(ihost, frame_index); break;
} case SCI_STP_DEV_CMD: case SCI_SMP_DEV_CMD: /* The device does not process any UF received from the hardware while *inthisstate.Allunsolicitedframesareforwardedtotheiorequest *object.
*/
status = sci_io_request_frame_handler(idev->working_request, frame_index); break;
}
struct sci_base_state_machine *sm = &idev->sm; enum sci_remote_device_states state = sm->current_state_id;
switch (state) { case SCI_DEV_READY: case SCI_STP_DEV_IDLE: case SCI_STP_DEV_CMD: case SCI_STP_DEV_NCQ: case SCI_STP_DEV_NCQ_ERROR: case SCI_STP_DEV_AWAIT_RESET: case SCI_SMP_DEV_IDLE: case SCI_SMP_DEV_CMD: returntrue; default: returnfalse;
}
}
switch (scu_get_event_type(event_code)) { case SCU_EVENT_TYPE_RNC_OPS_MISC: case SCU_EVENT_TYPE_RNC_SUSPEND_TX: case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
status = sci_remote_node_context_event_handler(&idev->rnc, event_code); break; case SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT: if (scu_get_event_code(event_code) == SCU_EVENT_IT_NEXUS_TIMEOUT) {
status = SCI_SUCCESS;
/* Suspend the associated RNC */
sci_remote_device_suspend(idev, SCI_SW_SUSPEND_NORMAL);
break;
}
fallthrough; /* and treat as unhandled */ default:
dev_dbg(scirdev_to_dev(idev), "%s: device: %p event code: %x: %s\n",
__func__, idev, event_code,
is_remote_device_ready(idev)
? "unexpected event"
: "unexpected event in wrong state");
status = SCI_FAILURE_INVALID_STATE; break;
}
if (status != SCI_SUCCESS) return status;
/* Decode device-specific states that may require an RNC resume during *normaloperation.Whentheabortpathisactive,theseresumesare *managedwhentheabortpathexits.
*/ if (state == SCI_STP_DEV_ATAPI_ERROR) { /* For ATAPI error state resume the RNC right away. */ if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX ||
scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX) { return sci_remote_node_context_resume(&idev->rnc,
atapi_remote_device_resume_done,
idev);
}
}
if (state == SCI_STP_DEV_IDLE) {
/* We pick up suspension events to handle specifically to this *state.WeresumetheRNCrightaway.
*/ if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX ||
scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX)
status = sci_remote_node_context_resume(&idev->rnc, NULL, NULL);
}
/* cleanup requests that failed after starting on the port */ if (status != SCI_SUCCESS)
sci_port_complete_io(iport, idev, ireq); else {
kref_get(&idev->kref);
idev->started_request_count++;
}
}
switch (state) { case SCI_DEV_INITIAL: case SCI_DEV_STOPPED: case SCI_DEV_STARTING: case SCI_STP_DEV_NCQ_ERROR: case SCI_DEV_STOPPING: case SCI_DEV_FAILED: case SCI_DEV_RESETTING: case SCI_DEV_FINAL: default:
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
__func__, dev_state_name(state)); return SCI_FAILURE_INVALID_STATE; case SCI_DEV_READY: /* attempt to start an io request for this device object. The remote *deviceobjectwillissuethestartrequestfortheioandif *successfulitwillstarttherequestfortheportobjectthen *incrementitsownrequestcount.
*/
status = sci_port_start_io(iport, idev, ireq); if (status != SCI_SUCCESS) return status;
status = sci_remote_node_context_start_io(&idev->rnc, ireq); if (status != SCI_SUCCESS) break;
status = sci_request_start(ireq); break; case SCI_STP_DEV_IDLE: { /* handle the start io operation for a sata device that is in *thecommandidlestate.-EvalutethetypeofIOrequestto *bestarted-IfitsanNCQrequestchangetoNCQsubstate- *IfitsanyothercommandchangetotheCMDsubstate * *Ifthisisasoftresetwemaywanttohaveadifferent *substate.
*/ enum sci_remote_device_states new_state; struct sas_task *task = isci_request_access_task(ireq);
status = sci_port_start_io(iport, idev, ireq); if (status != SCI_SUCCESS) return status;
status = sci_remote_node_context_start_io(&idev->rnc, ireq); if (status != SCI_SUCCESS) break;
status = sci_request_start(ireq); if (status != SCI_SUCCESS) break;
if (task->ata_task.use_ncq) {
status = sci_port_start_io(iport, idev, ireq); if (status != SCI_SUCCESS) return status;
status = sci_remote_node_context_start_io(&idev->rnc, ireq); if (status != SCI_SUCCESS) break;
status = sci_request_start(ireq);
} else return SCI_FAILURE_INVALID_STATE; break;
} case SCI_STP_DEV_AWAIT_RESET: return SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED; case SCI_SMP_DEV_IDLE:
status = sci_port_start_io(iport, idev, ireq); if (status != SCI_SUCCESS) return status;
status = sci_remote_node_context_start_io(&idev->rnc, ireq); if (status != SCI_SUCCESS) break;
status = sci_request_start(ireq); if (status != SCI_SUCCESS) break;
idev->working_request = ireq;
sci_change_state(&idev->sm, SCI_SMP_DEV_CMD); break; case SCI_STP_DEV_CMD: case SCI_SMP_DEV_CMD: /* device is already handling a command it can not accept new commands *untilthisoneiscomplete.
*/ return SCI_FAILURE_INVALID_STATE;
}
switch (state) { case SCI_DEV_INITIAL: case SCI_DEV_STOPPED: case SCI_DEV_STARTING: case SCI_STP_DEV_IDLE: case SCI_SMP_DEV_IDLE: case SCI_DEV_FAILED: case SCI_DEV_FINAL: default:
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
__func__, dev_state_name(state)); return SCI_FAILURE_INVALID_STATE; case SCI_DEV_READY: case SCI_STP_DEV_AWAIT_RESET: case SCI_DEV_RESETTING:
status = common_complete_io(iport, idev, ireq); break; case SCI_STP_DEV_CMD: case SCI_STP_DEV_NCQ: case SCI_STP_DEV_NCQ_ERROR: case SCI_STP_DEV_ATAPI_ERROR:
status = common_complete_io(iport, idev, ireq); if (status != SCI_SUCCESS) break;
if (ireq->sci_status == SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) { /* This request causes hardware error, device needs to be Lun Reset. *SohereweforcethestatemachinetoIDLEstatesotherestIOs *canreachRNCstatehandler,theseIOswillbecompletedbyRNCwith *statusof"DEVICE_RESET_REQUIRED",insteadof"INVALIDSTATE".
*/
sci_change_state(sm, SCI_STP_DEV_AWAIT_RESET);
} elseif (idev->started_request_count == 0)
sci_change_state(sm, SCI_STP_DEV_IDLE); break; case SCI_SMP_DEV_CMD:
status = common_complete_io(iport, idev, ireq); if (status != SCI_SUCCESS) break;
sci_change_state(sm, SCI_SMP_DEV_IDLE); break; case SCI_DEV_STOPPING:
status = common_complete_io(iport, idev, ireq); if (status != SCI_SUCCESS) break;
if (idev->started_request_count == 0)
sci_remote_node_context_destruct(&idev->rnc,
rnc_destruct_done,
idev); break;
}
switch (state) { case SCI_DEV_INITIAL: case SCI_DEV_STOPPED: case SCI_DEV_STARTING: case SCI_SMP_DEV_IDLE: case SCI_SMP_DEV_CMD: case SCI_DEV_STOPPING: case SCI_DEV_FAILED: case SCI_DEV_RESETTING: case SCI_DEV_FINAL: default:
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
__func__, dev_state_name(state)); return SCI_FAILURE_INVALID_STATE; case SCI_STP_DEV_IDLE: case SCI_STP_DEV_CMD: case SCI_STP_DEV_NCQ: case SCI_STP_DEV_NCQ_ERROR: case SCI_STP_DEV_AWAIT_RESET:
status = sci_port_start_io(iport, idev, ireq); if (status != SCI_SUCCESS) return status;
status = sci_request_start(ireq); if (status != SCI_SUCCESS) goto out;
/* Note: If the remote device state is not IDLE this will *replacetherequestthatprobablyresultedinthetask *managementrequest.
*/
idev->working_request = ireq;
sci_change_state(sm, SCI_STP_DEV_CMD);
/* The remote node context must cleanup the TCi to NCQ mapping *table.Theonlywaytodothiscorrectlyistoeitherwrite *totheTLCRregisterortoinvalidateandreposttheRNC.In *eithercasetheremotenodecontextstatemachinewilltake *thecorrectactionwhentheremotenodecontextissuspended *andlaterresumed.
*/
sci_remote_device_suspend(idev,
SCI_SW_SUSPEND_LINKHANG_DETECT);
status = sci_remote_node_context_start_task(&idev->rnc, ireq,
sci_remote_device_continue_request, idev);
out:
sci_remote_device_start_request(idev, ireq, status); /* We need to let the controller start request handler know that *itcan'tpostTCyet.Wewillprovideacallbackfunctionto *postTCwhenRNCgetsresumed.
*/ return SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS; case SCI_DEV_READY:
status = sci_port_start_io(iport, idev, ireq); if (status != SCI_SUCCESS) return status;
/* Resume the RNC as needed: */
status = sci_remote_node_context_start_task(&idev->rnc, ireq,
NULL, NULL); if (status != SCI_SUCCESS) break;
status = sci_request_start(ireq); break;
}
sci_remote_device_start_request(idev, ireq, status);
/* called once the remote node context has transisitioned to a *readystate.Thisistheindicationthattheremotedeviceobjectcanalso *transitiontoready.
*/ staticvoid remote_device_resume_done(void *_dev)
{ struct isci_remote_device *idev = _dev;
if (is_remote_device_ready(idev)) return;
/* go 'ready' if we are not already in a ready state */
sci_change_state(&idev->sm, SCI_DEV_READY);
}
/* For NCQ operation we do not issue a isci_remote_device_not_ready(). *Asaresult,avoidsendingthereadynotification.
*/ if (idev->sm.previous_state_id != SCI_STP_DEV_NCQ)
isci_remote_device_ready(ihost, idev);
}
/* There should not be any outstanding io's. All paths to *hereshouldgothroughisci_remote_device_nuke_requests. *Ifwehitthiscondition,wewillneedawaytocomplete
* io requests in process */
BUG_ON(idev->started_request_count > 0);
/* If we are entering from the stopping state let the SCI User know that *thestopoperationhascompleted.
*/
prev_state = idev->sm.previous_state_id; if (prev_state == SCI_DEV_STOPPING)
isci_remote_device_deconstruct(ihost, idev);
sci_port_get_properties(iport, &properties); /* Get accurate port width from port's phy mask for a DA device. */
idev->device_port_width = hweight32(properties.phy_mask);
status = sci_controller_allocate_remote_node_context(iport->owning_controller,
idev,
&idev->rnc.remote_node_index);
status = sci_controller_allocate_remote_node_context(iport->owning_controller,
idev,
&idev->rnc.remote_node_index); if (status != SCI_SUCCESS) return status;
/* For SAS-2 the physical link rate is actually a logical link *ratethatincorporatesmultiplexing.TheSCUdoesn't *incorporatemultiplexingandforthepurposesofthe *connectionthelogicallinkrateisthatsameasthe *physical.Furthermore,theSAS-2andSAS-1.1fieldsoverlay *oneanother,sothiscodeworksforbothsituations.
*/
idev->connection_rate = min_t(u16, sci_port_get_max_allowed_speed(iport),
dev->linkrate);
/* / @todo Should I assign the port width by reading all of the phys on the port? */
idev->device_port_width = 1;
if (dev->parent && dev_is_expander(dev->parent->dev_type))
status = sci_remote_device_ea_construct(iport, idev); else
status = sci_remote_device_da_construct(iport, idev);
set_bit(IDEV_STOP_PENDING, &idev->flags);
status = sci_remote_device_stop(idev, 50);
spin_unlock_irqrestore(&ihost->scic_lock, flags);
/* Wait for the stop complete callback. */ if (WARN_ONCE(status != SCI_SUCCESS, "failed to stop device\n")) /* nothing to wait for */; else
wait_for_device_stop(ihost, idev);
if (status == SCI_SUCCESS) { /* device came up, advertise it to the world */
dev->lldd_dev = isci_device;
} else
isci_put_device(isci_device);
spin_unlock_irq(&isci_host->scic_lock);
/* wait for the device ready callback. */
wait_for_device_start(isci_host, isci_device);
/* Put the device into suspension. */
spin_lock_irqsave(&ihost->scic_lock, flags);
set_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags);
sci_remote_device_suspend(idev, SCI_SW_SUSPEND_LINKHANG_DETECT);
spin_unlock_irqrestore(&ihost->scic_lock, flags);
/* Terminate and wait for the completions. */
status = isci_remote_device_terminate_requests(ihost, idev, ireq); if (status != SCI_SUCCESS)
dev_dbg(&ihost->pdev->dev, "%s: isci_remote_device_terminate_requests(%p) " "returned %d!\n",
__func__, idev, status);
/* NOTE: RNC resumption is left to the caller! */ return status;
}
int isci_remote_device_is_safe_to_abort( struct isci_remote_device *idev)
{ return sci_remote_node_context_is_safe_to_abort(&idev->rnc);
}
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.104Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-28)
¤
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.