Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 726980d5 authored by Jeff Skirvin's avatar Jeff Skirvin Committed by Dan Williams
Browse files

isci: Terminate outstanding TCs on TX/RX RNC suspensions.



TCs must only be terminated when RNCs are suspended.

Signed-off-by: default avatarJeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent ac78ed0f
Loading
Loading
Loading
Loading
+11 −11
Original line number Diff line number Diff line
@@ -2696,18 +2696,18 @@ enum sci_status sci_controller_terminate_request(struct isci_host *ihost,
			 __func__, ihost->sm.current_state_id);
		return SCI_FAILURE_INVALID_STATE;
	}

	status = sci_io_request_terminate(ireq);
	if (status != SCI_SUCCESS)
		return status;

	/*
	 * Utilize the original post context command and or in the POST_TC_ABORT
	 * request sub-type.
	if ((status == SCI_SUCCESS) &&
	    !test_bit(IREQ_PENDING_ABORT, &ireq->flags) &&
	    !test_and_set_bit(IREQ_TC_ABORT_POSTED, &ireq->flags)) {
		/* Utilize the original post context command and or in the
		 * POST_TC_ABORT request sub-type.
		 */
	sci_controller_post_request(ihost,
				    ireq->post_context | SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT);
	return SCI_SUCCESS;
		sci_controller_post_request(
			ihost, ireq->post_context |
				SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT);
	}
	return status;
}

/**
+95 −11
Original line number Diff line number Diff line
@@ -133,6 +133,50 @@ static void isci_remote_device_ready(struct isci_host *ihost, struct isci_remote
		wake_up(&ihost->eventq);
}

static enum sci_status sci_remote_device_suspend(
	struct isci_remote_device *idev)
{
	return sci_remote_node_context_suspend(
		&idev->rnc,
		SCI_SOFTWARE_SUSPENSION,
		SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT,
		NULL, NULL);
}

enum sci_status isci_remote_device_suspend(
	struct isci_host *ihost,
	struct isci_remote_device *idev)
{
	enum sci_status status;
	unsigned long flags;

	spin_lock_irqsave(&ihost->scic_lock, flags);

	if (isci_lookup_device(idev->domain_dev) == NULL) {
		spin_unlock_irqrestore(&ihost->scic_lock, flags);
		status = SCI_FAILURE;
	} else {
		status = sci_remote_device_suspend(idev);
		spin_unlock_irqrestore(&ihost->scic_lock, flags);
		if (status == SCI_SUCCESS) {
			wait_event(ihost->eventq,
				   test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
				|| !test_bit(IDEV_ALLOCATED, &idev->flags));

			status = test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
					? SCI_SUCCESS : SCI_FAILURE;
			dev_dbg(&ihost->pdev->dev,
				"%s: idev=%p, wait done, device is %s\n",
				__func__, idev,
				test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
					? "<suspended>" : "<deallocated!>");

		}
		isci_put_device(idev);
	}
	return status;
}

/* called once the remote node context is ready to be freed.
 * The remote device can now report that its stop operation is complete. none
 */
@@ -144,7 +188,9 @@ static void rnc_destruct_done(void *_dev)
	sci_change_state(&idev->sm, SCI_DEV_STOPPED);
}

static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_device *idev)
static enum sci_status sci_remote_device_terminate_requests_checkabort(
	struct isci_remote_device *idev,
	int check_abort_pending)
{
	struct isci_host *ihost = idev->owning_port->owning_controller;
	enum sci_status status  = SCI_SUCCESS;
@@ -155,7 +201,9 @@ static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_d
		enum sci_status s;

		if (!test_bit(IREQ_ACTIVE, &ireq->flags) ||
		    ireq->target_device != idev)
		    (ireq->target_device != idev) ||
		    (check_abort_pending && !test_bit(IREQ_PENDING_ABORT,
						      &ireq->flags)))
			continue;

		s = sci_controller_terminate_request(ihost, idev, ireq);
@@ -166,6 +214,12 @@ static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_d
	return status;
}

enum sci_status sci_remote_device_terminate_requests(
	struct isci_remote_device *idev)
{
	return sci_remote_device_terminate_requests_checkabort(idev, 0);
}

enum sci_status sci_remote_device_stop(struct isci_remote_device *idev,
					u32 timeout)
{
@@ -265,14 +319,6 @@ enum sci_status sci_remote_device_reset_complete(struct isci_remote_device *idev
	return SCI_SUCCESS;
}

enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev)
{
	return sci_remote_node_context_suspend(&idev->rnc,
					       SCI_SOFTWARE_SUSPENSION,
					       SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT,
					       NULL, NULL);
}

enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev,
						     u32 frame_index)
{
@@ -1413,3 +1459,41 @@ int isci_remote_device_found(struct domain_device *dev)

	return status == SCI_SUCCESS ? 0 : -ENODEV;
}

enum sci_status isci_remote_device_reset(
	struct isci_remote_device *idev)
{
	struct isci_host *ihost = dev_to_ihost(idev->domain_dev);
	unsigned long flags;
	enum sci_status status;

	/* Wait for the device suspend. */
	status = isci_remote_device_suspend(ihost, idev);
	if (status != SCI_SUCCESS) {
		dev_dbg(&ihost->pdev->dev,
			"%s: isci_remote_device_suspend(%p) returned %d!\n",
			__func__, idev, status);
		return status;
	}
	spin_lock_irqsave(&ihost->scic_lock, flags);
	status = sci_remote_device_reset(idev);
	spin_unlock_irqrestore(&ihost->scic_lock, flags);
	if (status != SCI_SUCCESS) {
		dev_dbg(&ihost->pdev->dev,
			"%s: sci_remote_device_reset(%p) returned %d!\n",
			__func__, idev, status);
	}
	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);
}

enum sci_status sci_remote_device_abort_requests_pending_abort(
	struct isci_remote_device *idev)
{
	return sci_remote_device_terminate_requests_checkabort(idev, 1);
}
+10 −0
Original line number Diff line number Diff line
@@ -85,6 +85,7 @@ struct isci_remote_device {
	#define IDEV_GONE 3
	#define IDEV_IO_READY 4
	#define IDEV_IO_NCQERROR 5
	#define IDEV_TXRX_SUSPENDED 6
	unsigned long flags;
	struct kref kref;
	struct isci_port *isci_port;
@@ -335,4 +336,13 @@ void sci_remote_device_post_request(
	struct isci_remote_device *idev,
	u32 request);

enum sci_status sci_remote_device_terminate_requests(
	struct isci_remote_device *idev);

int isci_remote_device_is_safe_to_abort(
	struct isci_remote_device *idev);

enum sci_status
sci_remote_device_abort_requests_pending_abort(
	struct isci_remote_device *idev);
#endif /* !defined(_ISCI_REMOTE_DEVICE_H_) */
+56 −0
Original line number Diff line number Diff line
@@ -268,6 +268,8 @@ static void sci_remote_node_context_invalidating_state_enter(struct sci_base_sta
{
	struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);

	/* Terminate outstanding requests pending abort. */
	sci_remote_device_abort_requests_pending_abort(rnc_to_dev(rnc));
	sci_remote_node_context_invalidate_context_buffer(rnc);
}

@@ -312,10 +314,28 @@ static void sci_remote_node_context_tx_suspended_state_enter(struct sci_base_sta
static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_state_machine *sm)
{
	struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
	struct isci_remote_device *idev = rnc_to_dev(rnc);
	struct isci_host *ihost = idev->owning_port->owning_controller;

	set_bit(IDEV_TXRX_SUSPENDED, &idev->flags);

	/* Terminate outstanding requests pending abort. */
	sci_remote_device_abort_requests_pending_abort(idev);

	wake_up(&ihost->eventq);
	sci_remote_node_context_continue_state_transitions(rnc);
}

static void sci_remote_node_context_tx_rx_suspended_state_exit(
	struct sci_base_state_machine *sm)
{
	struct sci_remote_node_context *rnc
		= container_of(sm, typeof(*rnc), sm);
	struct isci_remote_device *idev = rnc_to_dev(rnc);

	clear_bit(IDEV_TXRX_SUSPENDED, &idev->flags);
}

static void sci_remote_node_context_await_suspend_state_exit(
	struct sci_base_state_machine *sm)
{
@@ -346,6 +366,8 @@ static const struct sci_base_state sci_remote_node_context_state_table[] = {
	},
	[SCI_RNC_TX_RX_SUSPENDED] = {
		.enter_state = sci_remote_node_context_tx_rx_suspended_state_enter,
		.exit_state
			= sci_remote_node_context_tx_rx_suspended_state_exit,
	},
	[SCI_RNC_AWAIT_SUSPENSION] = {
		.exit_state = sci_remote_node_context_await_suspend_state_exit,
@@ -515,6 +537,13 @@ enum sci_status sci_remote_node_context_suspend(
	struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
	enum sci_status status = SCI_FAILURE_INVALID_STATE;

	dev_dbg(scirdev_to_dev(idev),
		"%s: current state %d, current suspend_type %x dest state %d,"
			" arg suspend_reason %d, arg suspend_type %x",
		__func__, state, sci_rnc->suspend_type,
		sci_rnc->destination_state, suspend_reason,
		suspend_type);

	/* Disable automatic state continuations if explicitly suspending. */
	if (suspend_reason == SCI_SOFTWARE_SUSPENSION)
		sci_rnc->destination_state
@@ -546,7 +575,10 @@ enum sci_status sci_remote_node_context_suspend(
	sci_rnc->suspend_type  = suspend_type;

	if (status == SCI_SUCCESS) { /* Already in the destination state? */
		struct isci_host *ihost = idev->owning_port->owning_controller;

		sci_remote_node_context_notify_user(sci_rnc);
		wake_up_all(&ihost->eventq); /* Let observers look. */
		return SCI_SUCCESS;
	}
	if (suspend_reason == SCI_SOFTWARE_SUSPENSION) {
@@ -661,3 +693,27 @@ enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_contex
		return SCI_FAILURE_INVALID_STATE;
	}
}

int sci_remote_node_context_is_safe_to_abort(
	struct sci_remote_node_context *sci_rnc)
{
	enum scis_sds_remote_node_context_states state;

	state = sci_rnc->sm.current_state_id;
	switch (state) {
	case SCI_RNC_INVALIDATING:
	case SCI_RNC_TX_RX_SUSPENDED:
		return 1;
	case SCI_RNC_POSTING:
	case SCI_RNC_RESUMING:
	case SCI_RNC_READY:
	case SCI_RNC_TX_SUSPENDED:
	case SCI_RNC_AWAIT_SUSPENSION:
	case SCI_RNC_INITIAL:
		return 0;
	default:
		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
			 "%s: invalid state %d\n", __func__, state);
		return 0;
	}
}
+2 −0
Original line number Diff line number Diff line
@@ -214,5 +214,7 @@ enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_contex
							struct isci_request *ireq);
enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context *sci_rnc,
						      struct isci_request *ireq);
int sci_remote_node_context_is_safe_to_abort(
	struct sci_remote_node_context *sci_rnc);

#endif  /* _SCIC_SDS_REMOTE_NODE_CONTEXT_H_ */
Loading