Exemplo n.º 1
0
int isci_task_I_T_nexus_reset(struct domain_device *dev)
{
	struct isci_host *ihost = dev_to_ihost(dev);
	struct isci_remote_device *idev;
	unsigned long flags;
	int ret;

	spin_lock_irqsave(&ihost->scic_lock, flags);
	idev = isci_lookup_device(dev);
	spin_unlock_irqrestore(&ihost->scic_lock, flags);

	if (!idev) {
		ret = TMF_RESP_FUNC_COMPLETE;
		goto out;
	}

	ret = isci_reset_device(ihost, dev, idev);
 out:
	isci_put_device(idev);
	return ret;
}
Exemplo n.º 2
0
int isci_task_lu_reset(struct domain_device *dev, u8 *lun)
{
	struct isci_host *isci_host = dev_to_ihost(dev);
	struct isci_remote_device *isci_device;
	unsigned long flags;
	int ret;

	spin_lock_irqsave(&isci_host->scic_lock, flags);
	isci_device = isci_lookup_device(dev);
	spin_unlock_irqrestore(&isci_host->scic_lock, flags);

	dev_dbg(&isci_host->pdev->dev,
		"%s: domain_device=%p, isci_host=%p; isci_device=%p\n",
		 __func__, dev, isci_host, isci_device);

	if (!isci_device) {
		/* If the device is gone, stop the escalations. */
		dev_dbg(&isci_host->pdev->dev, "%s: No dev\n", __func__);

		ret = TMF_RESP_FUNC_COMPLETE;
		goto out;
	}

	/* Send the task management part of the reset. */
	if (dev_is_sata(dev)) {
		sas_ata_schedule_reset(dev);
		ret = TMF_RESP_FUNC_COMPLETE;
	} else
		ret = isci_task_send_lu_reset_sas(isci_host, isci_device, lun);

	/* If the LUN reset worked, all the I/O can now be terminated. */
	if (ret == TMF_RESP_FUNC_COMPLETE)
		/* Terminate all I/O now. */
		isci_terminate_pending_requests(isci_host,
						isci_device);

 out:
	isci_put_device(isci_device);
	return ret;
}
Exemplo n.º 3
0
int isci_task_lu_reset(struct domain_device *dev, u8 *lun)
{
	struct isci_host *isci_host = dev_to_ihost(dev);
	struct isci_remote_device *isci_device;
	unsigned long flags;
	int ret;

	spin_lock_irqsave(&isci_host->scic_lock, flags);
	isci_device = isci_lookup_device(dev);
	spin_unlock_irqrestore(&isci_host->scic_lock, flags);

	dev_dbg(&isci_host->pdev->dev,
		"%s: domain_device=%p, isci_host=%p; isci_device=%p\n",
		 __func__, dev, isci_host, isci_device);

	if (!isci_device) {
		
		dev_dbg(&isci_host->pdev->dev, "%s: No dev\n", __func__);

		ret = TMF_RESP_FUNC_COMPLETE;
		goto out;
	}

	
	if (dev_is_sata(dev)) {
		sas_ata_schedule_reset(dev);
		ret = TMF_RESP_FUNC_COMPLETE;
	} else
		ret = isci_task_send_lu_reset_sas(isci_host, isci_device, lun);

	
	if (ret == TMF_RESP_FUNC_COMPLETE)
		
		isci_terminate_pending_requests(isci_host,
						isci_device);

 out:
	isci_put_device(isci_device);
	return ret;
}
int isci_task_I_T_nexus_reset(struct domain_device *dev)
{
	struct isci_host *ihost = dev_to_ihost(dev);
	struct isci_remote_device *idev;
	unsigned long flags;
	int ret;

	spin_lock_irqsave(&ihost->scic_lock, flags);
	idev = isci_lookup_device(dev);
	spin_unlock_irqrestore(&ihost->scic_lock, flags);

	if (!idev) {
		/* XXX: need to cleanup any ireqs targeting this
		 * domain_device
		 */
		ret = -ENODEV;
		goto out;
	}

	ret = isci_reset_device(ihost, dev, idev);
 out:
	isci_put_device(idev);
	return ret;
}
Exemplo n.º 5
0
/**
 * isci_task_execute_task() - This function is one of the SAS Domain Template
 *    functions. This function is called by libsas to send a task down to
 *    hardware.
 * @task: This parameter specifies the SAS task to send.
 * @num: This parameter specifies the number of tasks to queue.
 * @gfp_flags: This parameter specifies the context of this call.
 *
 * status, zero indicates success.
 */
int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
{
	struct isci_host *ihost = dev_to_ihost(task->dev);
	struct isci_remote_device *idev;
	unsigned long flags;
	bool io_ready;
	u16 tag;

	dev_dbg(&ihost->pdev->dev, "%s: num=%d\n", __func__, num);

	for_each_sas_task(num, task) {
		enum sci_status status = SCI_FAILURE;

		spin_lock_irqsave(&ihost->scic_lock, flags);
		idev = isci_lookup_device(task->dev);
		io_ready = isci_device_io_ready(idev, task);
		tag = isci_alloc_tag(ihost);
		spin_unlock_irqrestore(&ihost->scic_lock, flags);

		dev_dbg(&ihost->pdev->dev,
			"task: %p, num: %d dev: %p idev: %p:%#lx cmd = %p\n",
			task, num, task->dev, idev, idev ? idev->flags : 0,
			task->uldd_task);

		if (!idev) {
			isci_task_refuse(ihost, task, SAS_TASK_UNDELIVERED,
					 SAS_DEVICE_UNKNOWN);
		} else if (!io_ready || tag == SCI_CONTROLLER_INVALID_IO_TAG) {
			/* Indicate QUEUE_FULL so that the scsi midlayer
			 * retries.
			  */
			isci_task_refuse(ihost, task, SAS_TASK_COMPLETE,
					 SAS_QUEUE_FULL);
		} else {
			/* There is a device and it's ready for I/O. */
			spin_lock_irqsave(&task->task_state_lock, flags);

			if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
				/* The I/O was aborted. */
				spin_unlock_irqrestore(&task->task_state_lock,
						       flags);

				isci_task_refuse(ihost, task,
						 SAS_TASK_UNDELIVERED,
						 SAM_STAT_TASK_ABORTED);
			} else {
				task->task_state_flags |= SAS_TASK_AT_INITIATOR;
				spin_unlock_irqrestore(&task->task_state_lock, flags);

				/* build and send the request. */
				status = isci_request_execute(ihost, idev, task, tag);

				if (status != SCI_SUCCESS) {

					spin_lock_irqsave(&task->task_state_lock, flags);
					/* Did not really start this command. */
					task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
					spin_unlock_irqrestore(&task->task_state_lock, flags);

					if (test_bit(IDEV_GONE, &idev->flags)) {

						/* Indicate that the device
						 * is gone.
						 */
						isci_task_refuse(ihost, task,
							SAS_TASK_UNDELIVERED,
							SAS_DEVICE_UNKNOWN);
					} else {
						/* Indicate QUEUE_FULL so that
						 * the scsi midlayer retries.
						 * If the request failed for
						 * remote device reasons, it
						 * gets returned as
						 * SAS_TASK_UNDELIVERED next
						 * time through.
						 */
						isci_task_refuse(ihost, task,
							SAS_TASK_COMPLETE,
							SAS_QUEUE_FULL);
					}
				}
			}
		}
		if (status != SCI_SUCCESS && tag != SCI_CONTROLLER_INVALID_IO_TAG) {
			spin_lock_irqsave(&ihost->scic_lock, flags);
			/* command never hit the device, so just free
			 * the tci and skip the sequence increment
			 */
			isci_tci_free(ihost, ISCI_TAG_TCI(tag));
			spin_unlock_irqrestore(&ihost->scic_lock, flags);
		}
		isci_put_device(idev);
	}
	return 0;
}
Exemplo n.º 6
0
/**
 * isci_task_abort_task() - This function is one of the SAS Domain Template
 *    functions. This function is called by libsas to abort a specified task.
 * @task: This parameter specifies the SAS task to abort.
 *
 * status, zero indicates success.
 */
int isci_task_abort_task(struct sas_task *task)
{
	struct isci_host *isci_host = dev_to_ihost(task->dev);
	DECLARE_COMPLETION_ONSTACK(aborted_io_completion);
	struct isci_request       *old_request = NULL;
	enum isci_request_status  old_state;
	struct isci_remote_device *isci_device = NULL;
	struct isci_tmf           tmf;
	int                       ret = TMF_RESP_FUNC_FAILED;
	unsigned long             flags;
	int                       perform_termination = 0;

	/* Get the isci_request reference from the task.  Note that
	 * this check does not depend on the pending request list
	 * in the device, because tasks driving resets may land here
	 * after completion in the core.
	 */
	spin_lock_irqsave(&isci_host->scic_lock, flags);
	spin_lock(&task->task_state_lock);

	old_request = task->lldd_task;

	/* If task is already done, the request isn't valid */
	if (!(task->task_state_flags & SAS_TASK_STATE_DONE) &&
	    (task->task_state_flags & SAS_TASK_AT_INITIATOR) &&
	    old_request)
		isci_device = isci_lookup_device(task->dev);

	spin_unlock(&task->task_state_lock);
	spin_unlock_irqrestore(&isci_host->scic_lock, flags);

	dev_dbg(&isci_host->pdev->dev,
		"%s: dev = %p, task = %p, old_request == %p\n",
		__func__, isci_device, task, old_request);

	/* Device reset conditions signalled in task_state_flags are the
	 * responsbility of libsas to observe at the start of the error
	 * handler thread.
	 */
	if (!isci_device || !old_request) {
		/* The request has already completed and there
		* is nothing to do here other than to set the task
		* done bit, and indicate that the task abort function
		* was successful.
		*/
		spin_lock_irqsave(&task->task_state_lock, flags);
		task->task_state_flags |= SAS_TASK_STATE_DONE;
		task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
					    SAS_TASK_STATE_PENDING);
		spin_unlock_irqrestore(&task->task_state_lock, flags);

		ret = TMF_RESP_FUNC_COMPLETE;

		dev_dbg(&isci_host->pdev->dev,
			"%s: abort task not needed for %p\n",
			__func__, task);
		goto out;
	}

	spin_lock_irqsave(&isci_host->scic_lock, flags);

	/* Check the request status and change to "aborted" if currently
	 * "starting"; if true then set the I/O kernel completion
	 * struct that will be triggered when the request completes.
	 */
	old_state = isci_task_validate_request_to_abort(
				old_request, isci_host, isci_device,
				&aborted_io_completion);
	if ((old_state != started) &&
	    (old_state != completed) &&
	    (old_state != aborting)) {

		spin_unlock_irqrestore(&isci_host->scic_lock, flags);

		/* The request was already being handled by someone else (because
		* they got to set the state away from started).
		*/
		dev_dbg(&isci_host->pdev->dev,
			"%s:  device = %p; old_request %p already being aborted\n",
			__func__,
			isci_device, old_request);
		ret = TMF_RESP_FUNC_COMPLETE;
		goto out;
	}
	if (task->task_proto == SAS_PROTOCOL_SMP ||
	    sas_protocol_ata(task->task_proto) ||
	    test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) {

		spin_unlock_irqrestore(&isci_host->scic_lock, flags);

		dev_dbg(&isci_host->pdev->dev,
			"%s: %s request"
			" or complete_in_target (%d), thus no TMF\n",
			__func__,
			((task->task_proto == SAS_PROTOCOL_SMP)
				? "SMP"
				: (sas_protocol_ata(task->task_proto)
					? "SATA/STP"
					: "<other>")
			 ),
			test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags));

		if (test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) {
			spin_lock_irqsave(&task->task_state_lock, flags);
			task->task_state_flags |= SAS_TASK_STATE_DONE;
			task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
						    SAS_TASK_STATE_PENDING);
			spin_unlock_irqrestore(&task->task_state_lock, flags);
			ret = TMF_RESP_FUNC_COMPLETE;
		} else {
			spin_lock_irqsave(&task->task_state_lock, flags);
			task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
						    SAS_TASK_STATE_PENDING);
			spin_unlock_irqrestore(&task->task_state_lock, flags);
		}

		/* STP and SMP devices are not sent a TMF, but the
		 * outstanding I/O request is terminated below.  This is
		 * because SATA/STP and SMP discovery path timeouts directly
		 * call the abort task interface for cleanup.
		 */
		perform_termination = 1;

	} else {
		/* Fill in the tmf stucture */
		isci_task_build_abort_task_tmf(&tmf, isci_tmf_ssp_task_abort,
					       isci_abort_task_process_cb,
					       old_request);

		spin_unlock_irqrestore(&isci_host->scic_lock, flags);

		#define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* 1/2 second timeout */
		ret = isci_task_execute_tmf(isci_host, isci_device, &tmf,
					    ISCI_ABORT_TASK_TIMEOUT_MS);

		if (ret == TMF_RESP_FUNC_COMPLETE)
			perform_termination = 1;
		else
			dev_dbg(&isci_host->pdev->dev,
				"%s: isci_task_send_tmf failed\n", __func__);
	}
	if (perform_termination) {
		set_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags);

		/* Clean up the request on our side, and wait for the aborted
		 * I/O to complete.
		 */
		isci_terminate_request_core(isci_host, isci_device,
					    old_request);
	}

	/* Make sure we do not leave a reference to aborted_io_completion */
	old_request->io_request_completion = NULL;
 out:
	isci_put_device(isci_device);
	return ret;
}
Exemplo n.º 7
0
int isci_task_abort_task(struct sas_task *task)
{
	struct isci_host *isci_host = dev_to_ihost(task->dev);
	DECLARE_COMPLETION_ONSTACK(aborted_io_completion);
	struct isci_request       *old_request = NULL;
	enum isci_request_status  old_state;
	struct isci_remote_device *isci_device = NULL;
	struct isci_tmf           tmf;
	int                       ret = TMF_RESP_FUNC_FAILED;
	unsigned long             flags;
	int                       perform_termination = 0;

	spin_lock_irqsave(&isci_host->scic_lock, flags);
	spin_lock(&task->task_state_lock);

	old_request = task->lldd_task;

	
	if (!(task->task_state_flags & SAS_TASK_STATE_DONE) &&
	    (task->task_state_flags & SAS_TASK_AT_INITIATOR) &&
	    old_request)
		isci_device = isci_lookup_device(task->dev);

	spin_unlock(&task->task_state_lock);
	spin_unlock_irqrestore(&isci_host->scic_lock, flags);

	dev_dbg(&isci_host->pdev->dev,
		"%s: dev = %p, task = %p, old_request == %p\n",
		__func__, isci_device, task, old_request);

	if (!isci_device || !old_request) {
		spin_lock_irqsave(&task->task_state_lock, flags);
		task->task_state_flags |= SAS_TASK_STATE_DONE;
		task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
					    SAS_TASK_STATE_PENDING);
		spin_unlock_irqrestore(&task->task_state_lock, flags);

		ret = TMF_RESP_FUNC_COMPLETE;

		dev_dbg(&isci_host->pdev->dev,
			"%s: abort task not needed for %p\n",
			__func__, task);
		goto out;
	}

	spin_lock_irqsave(&isci_host->scic_lock, flags);

	old_state = isci_task_validate_request_to_abort(
				old_request, isci_host, isci_device,
				&aborted_io_completion);
	if ((old_state != started) &&
	    (old_state != completed) &&
	    (old_state != aborting)) {

		spin_unlock_irqrestore(&isci_host->scic_lock, flags);

		dev_dbg(&isci_host->pdev->dev,
			"%s:  device = %p; old_request %p already being aborted\n",
			__func__,
			isci_device, old_request);
		ret = TMF_RESP_FUNC_COMPLETE;
		goto out;
	}
	if (task->task_proto == SAS_PROTOCOL_SMP ||
	    sas_protocol_ata(task->task_proto) ||
	    test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) {

		spin_unlock_irqrestore(&isci_host->scic_lock, flags);

		dev_dbg(&isci_host->pdev->dev,
			"%s: %s request"
			" or complete_in_target (%d), thus no TMF\n",
			__func__,
			((task->task_proto == SAS_PROTOCOL_SMP)
				? "SMP"
				: (sas_protocol_ata(task->task_proto)
					? "SATA/STP"
					: "<other>")
			 ),
			test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags));

		if (test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) {
			spin_lock_irqsave(&task->task_state_lock, flags);
			task->task_state_flags |= SAS_TASK_STATE_DONE;
			task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
						    SAS_TASK_STATE_PENDING);
			spin_unlock_irqrestore(&task->task_state_lock, flags);
			ret = TMF_RESP_FUNC_COMPLETE;
		} else {
			spin_lock_irqsave(&task->task_state_lock, flags);
			task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
						    SAS_TASK_STATE_PENDING);
			spin_unlock_irqrestore(&task->task_state_lock, flags);
		}

		perform_termination = 1;

	} else {
		
		isci_task_build_abort_task_tmf(&tmf, isci_tmf_ssp_task_abort,
					       isci_abort_task_process_cb,
					       old_request);

		spin_unlock_irqrestore(&isci_host->scic_lock, flags);

		#define ISCI_ABORT_TASK_TIMEOUT_MS 500 
		ret = isci_task_execute_tmf(isci_host, isci_device, &tmf,
					    ISCI_ABORT_TASK_TIMEOUT_MS);

		if (ret == TMF_RESP_FUNC_COMPLETE)
			perform_termination = 1;
		else
			dev_dbg(&isci_host->pdev->dev,
				"%s: isci_task_send_tmf failed\n", __func__);
	}
	if (perform_termination) {
		set_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags);

		isci_terminate_request_core(isci_host, isci_device,
					    old_request);
	}

	
	old_request->io_request_completion = NULL;
 out:
	isci_put_device(isci_device);
	return ret;
}
Exemplo n.º 8
0
int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
{
	struct isci_host *ihost = dev_to_ihost(task->dev);
	struct isci_remote_device *idev;
	unsigned long flags;
	bool io_ready;
	u16 tag;

	dev_dbg(&ihost->pdev->dev, "%s: num=%d\n", __func__, num);

	for_each_sas_task(num, task) {
		enum sci_status status = SCI_FAILURE;

		spin_lock_irqsave(&ihost->scic_lock, flags);
		idev = isci_lookup_device(task->dev);
		io_ready = isci_device_io_ready(idev, task);
		tag = isci_alloc_tag(ihost);
		spin_unlock_irqrestore(&ihost->scic_lock, flags);

		dev_dbg(&ihost->pdev->dev,
			"task: %p, num: %d dev: %p idev: %p:%#lx cmd = %p\n",
			task, num, task->dev, idev, idev ? idev->flags : 0,
			task->uldd_task);

		if (!idev) {
			isci_task_refuse(ihost, task, SAS_TASK_UNDELIVERED,
					 SAS_DEVICE_UNKNOWN);
		} else if (!io_ready || tag == SCI_CONTROLLER_INVALID_IO_TAG) {
			isci_task_refuse(ihost, task, SAS_TASK_COMPLETE,
					 SAS_QUEUE_FULL);
		} else {
			
			spin_lock_irqsave(&task->task_state_lock, flags);

			if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
				
				spin_unlock_irqrestore(&task->task_state_lock,
						       flags);

				isci_task_refuse(ihost, task,
						 SAS_TASK_UNDELIVERED,
						 SAM_STAT_TASK_ABORTED);
			} else {
				task->task_state_flags |= SAS_TASK_AT_INITIATOR;
				spin_unlock_irqrestore(&task->task_state_lock, flags);

				
				status = isci_request_execute(ihost, idev, task, tag);

				if (status != SCI_SUCCESS) {

					spin_lock_irqsave(&task->task_state_lock, flags);
					
					task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
					spin_unlock_irqrestore(&task->task_state_lock, flags);

					if (test_bit(IDEV_GONE, &idev->flags)) {

						isci_task_refuse(ihost, task,
							SAS_TASK_UNDELIVERED,
							SAS_DEVICE_UNKNOWN);
					} else {
						isci_task_refuse(ihost, task,
							SAS_TASK_COMPLETE,
							SAS_QUEUE_FULL);
					}
				}
			}
		}
		if (status != SCI_SUCCESS && tag != SCI_CONTROLLER_INVALID_IO_TAG) {
			spin_lock_irqsave(&ihost->scic_lock, flags);
			isci_tci_free(ihost, ISCI_TAG_TCI(tag));
			spin_unlock_irqrestore(&ihost->scic_lock, flags);
		}
		isci_put_device(idev);
	}
	return 0;
}