16f231dda68080759f1aed3769896e94c73099f0fDan Williams/*
26f231dda68080759f1aed3769896e94c73099f0fDan Williams * This file is provided under a dual BSD/GPLv2 license.  When using or
36f231dda68080759f1aed3769896e94c73099f0fDan Williams * redistributing this file, you may do so under either license.
46f231dda68080759f1aed3769896e94c73099f0fDan Williams *
56f231dda68080759f1aed3769896e94c73099f0fDan Williams * GPL LICENSE SUMMARY
66f231dda68080759f1aed3769896e94c73099f0fDan Williams *
76f231dda68080759f1aed3769896e94c73099f0fDan Williams * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
86f231dda68080759f1aed3769896e94c73099f0fDan Williams *
96f231dda68080759f1aed3769896e94c73099f0fDan Williams * This program is free software; you can redistribute it and/or modify
106f231dda68080759f1aed3769896e94c73099f0fDan Williams * it under the terms of version 2 of the GNU General Public License as
116f231dda68080759f1aed3769896e94c73099f0fDan Williams * published by the Free Software Foundation.
126f231dda68080759f1aed3769896e94c73099f0fDan Williams *
136f231dda68080759f1aed3769896e94c73099f0fDan Williams * This program is distributed in the hope that it will be useful, but
146f231dda68080759f1aed3769896e94c73099f0fDan Williams * WITHOUT ANY WARRANTY; without even the implied warranty of
156f231dda68080759f1aed3769896e94c73099f0fDan Williams * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
166f231dda68080759f1aed3769896e94c73099f0fDan Williams * General Public License for more details.
176f231dda68080759f1aed3769896e94c73099f0fDan Williams *
186f231dda68080759f1aed3769896e94c73099f0fDan Williams * You should have received a copy of the GNU General Public License
196f231dda68080759f1aed3769896e94c73099f0fDan Williams * along with this program; if not, write to the Free Software
206f231dda68080759f1aed3769896e94c73099f0fDan Williams * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
216f231dda68080759f1aed3769896e94c73099f0fDan Williams * The full GNU General Public License is included in this distribution
226f231dda68080759f1aed3769896e94c73099f0fDan Williams * in the file called LICENSE.GPL.
236f231dda68080759f1aed3769896e94c73099f0fDan Williams *
246f231dda68080759f1aed3769896e94c73099f0fDan Williams * BSD LICENSE
256f231dda68080759f1aed3769896e94c73099f0fDan Williams *
266f231dda68080759f1aed3769896e94c73099f0fDan Williams * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
276f231dda68080759f1aed3769896e94c73099f0fDan Williams * All rights reserved.
286f231dda68080759f1aed3769896e94c73099f0fDan Williams *
296f231dda68080759f1aed3769896e94c73099f0fDan Williams * Redistribution and use in source and binary forms, with or without
306f231dda68080759f1aed3769896e94c73099f0fDan Williams * modification, are permitted provided that the following conditions
316f231dda68080759f1aed3769896e94c73099f0fDan Williams * are met:
326f231dda68080759f1aed3769896e94c73099f0fDan Williams *
336f231dda68080759f1aed3769896e94c73099f0fDan Williams *   * Redistributions of source code must retain the above copyright
346f231dda68080759f1aed3769896e94c73099f0fDan Williams *     notice, this list of conditions and the following disclaimer.
356f231dda68080759f1aed3769896e94c73099f0fDan Williams *   * Redistributions in binary form must reproduce the above copyright
366f231dda68080759f1aed3769896e94c73099f0fDan Williams *     notice, this list of conditions and the following disclaimer in
376f231dda68080759f1aed3769896e94c73099f0fDan Williams *     the documentation and/or other materials provided with the
386f231dda68080759f1aed3769896e94c73099f0fDan Williams *     distribution.
396f231dda68080759f1aed3769896e94c73099f0fDan Williams *   * Neither the name of Intel Corporation nor the names of its
406f231dda68080759f1aed3769896e94c73099f0fDan Williams *     contributors may be used to endorse or promote products derived
416f231dda68080759f1aed3769896e94c73099f0fDan Williams *     from this software without specific prior written permission.
426f231dda68080759f1aed3769896e94c73099f0fDan Williams *
436f231dda68080759f1aed3769896e94c73099f0fDan Williams * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
446f231dda68080759f1aed3769896e94c73099f0fDan Williams * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
456f231dda68080759f1aed3769896e94c73099f0fDan Williams * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
466f231dda68080759f1aed3769896e94c73099f0fDan Williams * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
476f231dda68080759f1aed3769896e94c73099f0fDan Williams * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
486f231dda68080759f1aed3769896e94c73099f0fDan Williams * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
496f231dda68080759f1aed3769896e94c73099f0fDan Williams * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
506f231dda68080759f1aed3769896e94c73099f0fDan Williams * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
516f231dda68080759f1aed3769896e94c73099f0fDan Williams * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
526f231dda68080759f1aed3769896e94c73099f0fDan Williams * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
536f231dda68080759f1aed3769896e94c73099f0fDan Williams * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
546f231dda68080759f1aed3769896e94c73099f0fDan Williams */
556f231dda68080759f1aed3769896e94c73099f0fDan Williams
566f231dda68080759f1aed3769896e94c73099f0fDan Williams#include <linux/completion.h>
5750e7f9b5a9ae4a763b2c27500807cf237faca9b0Dan Williams#include <linux/irqflags.h>
58af5ae89350840b9d724fc4fb81d928673bffdd4dDave Jiang#include "sas.h"
5961aaff49e20fdb700f1300a49962bc76effc77fcJeff Skirvin#include <scsi/libsas.h>
6088f3b62ac131e2549b6c262cacbd47e8cca42d6eDan Williams#include "remote_device.h"
6188f3b62ac131e2549b6c262cacbd47e8cca42d6eDan Williams#include "remote_node_context.h"
626f231dda68080759f1aed3769896e94c73099f0fDan Williams#include "isci.h"
636f231dda68080759f1aed3769896e94c73099f0fDan Williams#include "request.h"
646f231dda68080759f1aed3769896e94c73099f0fDan Williams#include "task.h"
65312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams#include "host.h"
66af5ae89350840b9d724fc4fb81d928673bffdd4dDave Jiang
6750e7f9b5a9ae4a763b2c27500807cf237faca9b0Dan Williams/**
681077a574103177bff22b7cdd155d960f46ac1e8fDan Williams* isci_task_refuse() - complete the request to the upper layer driver in
691077a574103177bff22b7cdd155d960f46ac1e8fDan Williams*     the case where an I/O needs to be completed back in the submit path.
701077a574103177bff22b7cdd155d960f46ac1e8fDan Williams* @ihost: host on which the the request was queued
711077a574103177bff22b7cdd155d960f46ac1e8fDan Williams* @task: request to complete
721077a574103177bff22b7cdd155d960f46ac1e8fDan Williams* @response: response code for the completed task.
731077a574103177bff22b7cdd155d960f46ac1e8fDan Williams* @status: status code for the completed task.
7450e7f9b5a9ae4a763b2c27500807cf237faca9b0Dan Williams*
7550e7f9b5a9ae4a763b2c27500807cf237faca9b0Dan Williams*/
761077a574103177bff22b7cdd155d960f46ac1e8fDan Williamsstatic void isci_task_refuse(struct isci_host *ihost, struct sas_task *task,
771077a574103177bff22b7cdd155d960f46ac1e8fDan Williams			     enum service_response response,
781077a574103177bff22b7cdd155d960f46ac1e8fDan Williams			     enum exec_status status)
791077a574103177bff22b7cdd155d960f46ac1e8fDan Williams
8050e7f9b5a9ae4a763b2c27500807cf237faca9b0Dan Williams{
811077a574103177bff22b7cdd155d960f46ac1e8fDan Williams	enum isci_completion_selection disposition;
8250e7f9b5a9ae4a763b2c27500807cf237faca9b0Dan Williams
831077a574103177bff22b7cdd155d960f46ac1e8fDan Williams	disposition = isci_perform_normal_io_completion;
841077a574103177bff22b7cdd155d960f46ac1e8fDan Williams	disposition = isci_task_set_completion_status(task, response, status,
851077a574103177bff22b7cdd155d960f46ac1e8fDan Williams						      disposition);
8650e7f9b5a9ae4a763b2c27500807cf237faca9b0Dan Williams
8750e7f9b5a9ae4a763b2c27500807cf237faca9b0Dan Williams	/* Tasks aborted specifically by a call to the lldd_abort_task
881077a574103177bff22b7cdd155d960f46ac1e8fDan Williams	 * function should not be completed to the host in the regular path.
891077a574103177bff22b7cdd155d960f46ac1e8fDan Williams	 */
901077a574103177bff22b7cdd155d960f46ac1e8fDan Williams	switch (disposition) {
91a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley	case isci_perform_normal_io_completion:
92a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley		/* Normal notification (task_done) */
93a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley		dev_dbg(&ihost->pdev->dev,
94a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley			"%s: Normal - task = %p, response=%d, "
95a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley			"status=%d\n",
96a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley			__func__, task, response, status);
9750e7f9b5a9ae4a763b2c27500807cf237faca9b0Dan Williams
98a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley		task->lldd_task = NULL;
99312d3e56119a4bc5c36a96818f87f650c069ddc2Dan Williams		task->task_done(task);
100a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley		break;
10150e7f9b5a9ae4a763b2c27500807cf237faca9b0Dan Williams
102a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley	case isci_perform_aborted_io_completion:
103a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley		/*
104a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley		 * No notification because this request is already in the
105a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley		 * abort path.
106a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley		 */
107a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley		dev_dbg(&ihost->pdev->dev,
108a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley			"%s: Aborted - task = %p, response=%d, "
109a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley			"status=%d\n",
110a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley			__func__, task, response, status);
111a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley		break;
11250e7f9b5a9ae4a763b2c27500807cf237faca9b0Dan Williams
113a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley	case isci_perform_error_io_completion:
114a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley		/* Use sas_task_abort */
115a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley		dev_dbg(&ihost->pdev->dev,
116a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley			"%s: Error - task = %p, response=%d, "
117a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley			"status=%d\n",
118a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley			__func__, task, response, status);
119312d3e56119a4bc5c36a96818f87f650c069ddc2Dan Williams		sas_task_abort(task);
120a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley		break;
12150e7f9b5a9ae4a763b2c27500807cf237faca9b0Dan Williams
122a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley	default:
123a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley		dev_dbg(&ihost->pdev->dev,
124a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley			"%s: isci task notification default case!",
125a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley			__func__);
126a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley		sas_task_abort(task);
127a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley		break;
12850e7f9b5a9ae4a763b2c27500807cf237faca9b0Dan Williams	}
12950e7f9b5a9ae4a763b2c27500807cf237faca9b0Dan Williams}
1306f231dda68080759f1aed3769896e94c73099f0fDan Williams
1311077a574103177bff22b7cdd155d960f46ac1e8fDan Williams#define for_each_sas_task(num, task) \
1321077a574103177bff22b7cdd155d960f46ac1e8fDan Williams	for (; num > 0; num--,\
1331077a574103177bff22b7cdd155d960f46ac1e8fDan Williams	     task = list_entry(task->list.next, struct sas_task, list))
1341077a574103177bff22b7cdd155d960f46ac1e8fDan Williams
1359274f45ea551421cd3bf329de9dd8d1e6208285aJeff Skirvin
1369274f45ea551421cd3bf329de9dd8d1e6208285aJeff Skirvinstatic inline int isci_device_io_ready(struct isci_remote_device *idev,
1379274f45ea551421cd3bf329de9dd8d1e6208285aJeff Skirvin				       struct sas_task *task)
1389274f45ea551421cd3bf329de9dd8d1e6208285aJeff Skirvin{
1399274f45ea551421cd3bf329de9dd8d1e6208285aJeff Skirvin	return idev ? test_bit(IDEV_IO_READY, &idev->flags) ||
1409274f45ea551421cd3bf329de9dd8d1e6208285aJeff Skirvin		      (test_bit(IDEV_IO_NCQERROR, &idev->flags) &&
1419274f45ea551421cd3bf329de9dd8d1e6208285aJeff Skirvin		       isci_task_is_ncq_recovery(task))
1429274f45ea551421cd3bf329de9dd8d1e6208285aJeff Skirvin		    : 0;
1439274f45ea551421cd3bf329de9dd8d1e6208285aJeff Skirvin}
1446f231dda68080759f1aed3769896e94c73099f0fDan Williams/**
1456f231dda68080759f1aed3769896e94c73099f0fDan Williams * isci_task_execute_task() - This function is one of the SAS Domain Template
1466f231dda68080759f1aed3769896e94c73099f0fDan Williams *    functions. This function is called by libsas to send a task down to
1476f231dda68080759f1aed3769896e94c73099f0fDan Williams *    hardware.
1486f231dda68080759f1aed3769896e94c73099f0fDan Williams * @task: This parameter specifies the SAS task to send.
1496f231dda68080759f1aed3769896e94c73099f0fDan Williams * @num: This parameter specifies the number of tasks to queue.
1506f231dda68080759f1aed3769896e94c73099f0fDan Williams * @gfp_flags: This parameter specifies the context of this call.
1516f231dda68080759f1aed3769896e94c73099f0fDan Williams *
1526f231dda68080759f1aed3769896e94c73099f0fDan Williams * status, zero indicates success.
1536f231dda68080759f1aed3769896e94c73099f0fDan Williams */
1546f231dda68080759f1aed3769896e94c73099f0fDan Williamsint isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
1556f231dda68080759f1aed3769896e94c73099f0fDan Williams{
1564393aa4e6b9517a666f0ef6b774fd421a9dc4c68Dan Williams	struct isci_host *ihost = dev_to_ihost(task->dev);
157209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	struct isci_remote_device *idev;
1586f231dda68080759f1aed3769896e94c73099f0fDan Williams	unsigned long flags;
159f2088267514b39af1a94409168101527769a911cDan Williams	bool io_ready;
160312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams	u16 tag;
1616f231dda68080759f1aed3769896e94c73099f0fDan Williams
1621077a574103177bff22b7cdd155d960f46ac1e8fDan Williams	dev_dbg(&ihost->pdev->dev, "%s: num=%d\n", __func__, num);
1636f231dda68080759f1aed3769896e94c73099f0fDan Williams
1641077a574103177bff22b7cdd155d960f46ac1e8fDan Williams	for_each_sas_task(num, task) {
165312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams		enum sci_status status = SCI_FAILURE;
166312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams
167209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams		spin_lock_irqsave(&ihost->scic_lock, flags);
168209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams		idev = isci_lookup_device(task->dev);
1699274f45ea551421cd3bf329de9dd8d1e6208285aJeff Skirvin		io_ready = isci_device_io_ready(idev, task);
170312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams		tag = isci_alloc_tag(ihost);
171209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams		spin_unlock_irqrestore(&ihost->scic_lock, flags);
1726f231dda68080759f1aed3769896e94c73099f0fDan Williams
173f2088267514b39af1a94409168101527769a911cDan Williams		dev_dbg(&ihost->pdev->dev,
174f2088267514b39af1a94409168101527769a911cDan Williams			"task: %p, num: %d dev: %p idev: %p:%#lx cmd = %p\n",
175f2088267514b39af1a94409168101527769a911cDan Williams			task, num, task->dev, idev, idev ? idev->flags : 0,
176f2088267514b39af1a94409168101527769a911cDan Williams			task->uldd_task);
1776f231dda68080759f1aed3769896e94c73099f0fDan Williams
178f2088267514b39af1a94409168101527769a911cDan Williams		if (!idev) {
179f2088267514b39af1a94409168101527769a911cDan Williams			isci_task_refuse(ihost, task, SAS_TASK_UNDELIVERED,
180f2088267514b39af1a94409168101527769a911cDan Williams					 SAS_DEVICE_UNKNOWN);
181312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams		} else if (!io_ready || tag == SCI_CONTROLLER_INVALID_IO_TAG) {
182f2088267514b39af1a94409168101527769a911cDan Williams			/* Indicate QUEUE_FULL so that the scsi midlayer
183f2088267514b39af1a94409168101527769a911cDan Williams			 * retries.
184f2088267514b39af1a94409168101527769a911cDan Williams			  */
185f2088267514b39af1a94409168101527769a911cDan Williams			isci_task_refuse(ihost, task, SAS_TASK_COMPLETE,
186f2088267514b39af1a94409168101527769a911cDan Williams					 SAS_QUEUE_FULL);
187f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin		} else {
188f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin			/* There is a device and it's ready for I/O. */
189f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin			spin_lock_irqsave(&task->task_state_lock, flags);
1906f231dda68080759f1aed3769896e94c73099f0fDan Williams
191f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin			if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
192f2088267514b39af1a94409168101527769a911cDan Williams				/* The I/O was aborted. */
193f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin				spin_unlock_irqrestore(&task->task_state_lock,
194f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin						       flags);
1956f231dda68080759f1aed3769896e94c73099f0fDan Williams
1961077a574103177bff22b7cdd155d960f46ac1e8fDan Williams				isci_task_refuse(ihost, task,
1971077a574103177bff22b7cdd155d960f46ac1e8fDan Williams						 SAS_TASK_UNDELIVERED,
1981077a574103177bff22b7cdd155d960f46ac1e8fDan Williams						 SAM_STAT_TASK_ABORTED);
199f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin			} else {
2006f231dda68080759f1aed3769896e94c73099f0fDan Williams				task->task_state_flags |= SAS_TASK_AT_INITIATOR;
2016f231dda68080759f1aed3769896e94c73099f0fDan Williams				spin_unlock_irqrestore(&task->task_state_lock, flags);
202f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin
203f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin				/* build and send the request. */
204db0562509800a2d4cb5cb14a66413c30484f165cDan Williams				status = isci_request_execute(ihost, idev, task, tag);
205f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin
206f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin				if (status != SCI_SUCCESS) {
207f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin
208f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin					spin_lock_irqsave(&task->task_state_lock, flags);
209f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin					/* Did not really start this command. */
210f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin					task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
211f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin					spin_unlock_irqrestore(&task->task_state_lock, flags);
212f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin
213c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin					if (test_bit(IDEV_GONE, &idev->flags)) {
214c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin
215c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin						/* Indicate that the device
216c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin						 * is gone.
217c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin						 */
218c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin						isci_task_refuse(ihost, task,
219c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin							SAS_TASK_UNDELIVERED,
220c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin							SAS_DEVICE_UNKNOWN);
221c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin					} else {
222c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin						/* Indicate QUEUE_FULL so that
223c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin						 * the scsi midlayer retries.
224c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin						 * If the request failed for
225c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin						 * remote device reasons, it
226c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin						 * gets returned as
227c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin						 * SAS_TASK_UNDELIVERED next
228c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin						 * time through.
229c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin						 */
230c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin						isci_task_refuse(ihost, task,
231c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin							SAS_TASK_COMPLETE,
232c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin							SAS_QUEUE_FULL);
233c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3Jeff Skirvin					}
234f0846c68912545d70da16b2fbedded37ea4394d8Jeff Skirvin				}
2356f231dda68080759f1aed3769896e94c73099f0fDan Williams			}
2366f231dda68080759f1aed3769896e94c73099f0fDan Williams		}
237312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams		if (status != SCI_SUCCESS && tag != SCI_CONTROLLER_INVALID_IO_TAG) {
238312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams			spin_lock_irqsave(&ihost->scic_lock, flags);
239312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams			/* command never hit the device, so just free
240312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams			 * the tci and skip the sequence increment
241312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams			 */
242312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams			isci_tci_free(ihost, ISCI_TAG_TCI(tag));
243312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams			spin_unlock_irqrestore(&ihost->scic_lock, flags);
244312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams		}
245209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams		isci_put_device(idev);
2461077a574103177bff22b7cdd155d960f46ac1e8fDan Williams	}
2476f231dda68080759f1aed3769896e94c73099f0fDan Williams	return 0;
2486f231dda68080759f1aed3769896e94c73099f0fDan Williams}
2496f231dda68080759f1aed3769896e94c73099f0fDan Williams
2500d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williamsstatic struct isci_request *isci_task_request_build(struct isci_host *ihost,
251209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams						    struct isci_remote_device *idev,
252312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams						    u16 tag, struct isci_tmf *isci_tmf)
2536f231dda68080759f1aed3769896e94c73099f0fDan Williams{
2546f231dda68080759f1aed3769896e94c73099f0fDan Williams	enum sci_status status = SCI_FAILURE;
2550d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams	struct isci_request *ireq = NULL;
256a1a113b0a1ea437daf099b44f8a39e93a02a3f47Dan Williams	struct domain_device *dev;
2576f231dda68080759f1aed3769896e94c73099f0fDan Williams
2580d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams	dev_dbg(&ihost->pdev->dev,
2596f231dda68080759f1aed3769896e94c73099f0fDan Williams		"%s: isci_tmf = %p\n", __func__, isci_tmf);
2606f231dda68080759f1aed3769896e94c73099f0fDan Williams
2610d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams	dev = idev->domain_dev;
2626f231dda68080759f1aed3769896e94c73099f0fDan Williams
2636f231dda68080759f1aed3769896e94c73099f0fDan Williams	/* do common allocation and init of request object. */
264db0562509800a2d4cb5cb14a66413c30484f165cDan Williams	ireq = isci_tmf_request_from_tag(ihost, isci_tmf, tag);
2650d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams	if (!ireq)
2660d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams		return NULL;
2676f231dda68080759f1aed3769896e94c73099f0fDan Williams
2686f231dda68080759f1aed3769896e94c73099f0fDan Williams	/* let the core do it's construct. */
26989a7301f21fb00e753089671eb9e4132aab8ea08Dan Williams	status = sci_task_request_construct(ihost, idev, tag,
2705076a1a97e2fa61c847a5fdd4b1991faf7716da6Dan Williams					     ireq);
2716f231dda68080759f1aed3769896e94c73099f0fDan Williams
2726f231dda68080759f1aed3769896e94c73099f0fDan Williams	if (status != SCI_SUCCESS) {
2730d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams		dev_warn(&ihost->pdev->dev,
27489a7301f21fb00e753089671eb9e4132aab8ea08Dan Williams			 "%s: sci_task_request_construct failed - "
2756f231dda68080759f1aed3769896e94c73099f0fDan Williams			 "status = 0x%x\n",
2766f231dda68080759f1aed3769896e94c73099f0fDan Williams			 __func__,
2776f231dda68080759f1aed3769896e94c73099f0fDan Williams			 status);
278db0562509800a2d4cb5cb14a66413c30484f165cDan Williams		return NULL;
2796f231dda68080759f1aed3769896e94c73099f0fDan Williams	}
2806f231dda68080759f1aed3769896e94c73099f0fDan Williams
281a1a113b0a1ea437daf099b44f8a39e93a02a3f47Dan Williams	/* XXX convert to get this from task->tproto like other drivers */
282a1a113b0a1ea437daf099b44f8a39e93a02a3f47Dan Williams	if (dev->dev_type == SAS_END_DEV) {
2836f231dda68080759f1aed3769896e94c73099f0fDan Williams		isci_tmf->proto = SAS_PROTOCOL_SSP;
28489a7301f21fb00e753089671eb9e4132aab8ea08Dan Williams		status = sci_task_request_construct_ssp(ireq);
2856f231dda68080759f1aed3769896e94c73099f0fDan Williams		if (status != SCI_SUCCESS)
286db0562509800a2d4cb5cb14a66413c30484f165cDan Williams			return NULL;
2876f231dda68080759f1aed3769896e94c73099f0fDan Williams	}
2886f231dda68080759f1aed3769896e94c73099f0fDan Williams
2890d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams	return ireq;
2906f231dda68080759f1aed3769896e94c73099f0fDan Williams}
2916f231dda68080759f1aed3769896e94c73099f0fDan Williams
292b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin/**
293b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin* isci_request_mark_zombie() - This function must be called with scic_lock held.
294b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin*/
295b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvinstatic void isci_request_mark_zombie(struct isci_host *ihost, struct isci_request *ireq)
296b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin{
297b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	struct completion *tmf_completion = NULL;
298b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	struct completion *req_completion;
299b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin
300b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	/* Set the request state to "dead". */
301b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	ireq->status = dead;
302b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin
303b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	req_completion = ireq->io_request_completion;
304b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	ireq->io_request_completion = NULL;
305b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin
3063b34c169f8197e02529fa3ec703703c2ce418c57Jeff Skirvin	if (test_bit(IREQ_TMF, &ireq->flags)) {
307b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		/* Break links with the TMF request. */
308b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		struct isci_tmf *tmf = isci_request_access_tmf(ireq);
309b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin
310b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		/* In the case where a task request is dying,
311b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		 * the thread waiting on the complete will sit and
312b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		 * timeout unless we wake it now.  Since the TMF
313b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		 * has a default error status, complete it here
314b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		 * to wake the waiting thread.
315b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		 */
316b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		if (tmf) {
317b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			tmf_completion = tmf->complete;
318b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			tmf->complete = NULL;
319b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		}
320b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		ireq->ttype_ptr.tmf_task_ptr = NULL;
321b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		dev_dbg(&ihost->pdev->dev, "%s: tmf_code %d, managed tag %#x\n",
322b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			__func__, tmf->tmf_code, tmf->io_tag);
3233b34c169f8197e02529fa3ec703703c2ce418c57Jeff Skirvin	} else {
3243b34c169f8197e02529fa3ec703703c2ce418c57Jeff Skirvin		/* Break links with the sas_task - the callback is done
3253b34c169f8197e02529fa3ec703703c2ce418c57Jeff Skirvin		 * elsewhere.
3263b34c169f8197e02529fa3ec703703c2ce418c57Jeff Skirvin		 */
3273b34c169f8197e02529fa3ec703703c2ce418c57Jeff Skirvin		struct sas_task *task = isci_request_access_task(ireq);
3283b34c169f8197e02529fa3ec703703c2ce418c57Jeff Skirvin
3293b34c169f8197e02529fa3ec703703c2ce418c57Jeff Skirvin		if (task)
3303b34c169f8197e02529fa3ec703703c2ce418c57Jeff Skirvin			task->lldd_task = NULL;
3313b34c169f8197e02529fa3ec703703c2ce418c57Jeff Skirvin
3323b34c169f8197e02529fa3ec703703c2ce418c57Jeff Skirvin		ireq->ttype_ptr.io_task_ptr = NULL;
333b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	}
334b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin
335b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	dev_warn(&ihost->pdev->dev, "task context unrecoverable (tag: %#x)\n",
336b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		 ireq->io_tag);
337b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin
338b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	/* Don't force waiting threads to timeout. */
339b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	if (req_completion)
340b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		complete(req_completion);
341b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin
342b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	if (tmf_completion != NULL)
343b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		complete(tmf_completion);
344b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin}
345b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin
34616ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williamsstatic int isci_task_execute_tmf(struct isci_host *ihost,
34716ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williams				 struct isci_remote_device *idev,
34816ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williams				 struct isci_tmf *tmf, unsigned long timeout_ms)
3496f231dda68080759f1aed3769896e94c73099f0fDan Williams{
3506f231dda68080759f1aed3769896e94c73099f0fDan Williams	DECLARE_COMPLETION_ONSTACK(completion);
351467e855a0331f619f41fbf7391bc29ec0ca923a0Bartosz Barcinski	enum sci_task_status status = SCI_TASK_FAILURE;
3520d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams	struct isci_request *ireq;
3536f231dda68080759f1aed3769896e94c73099f0fDan Williams	int ret = TMF_RESP_FUNC_FAILED;
3546f231dda68080759f1aed3769896e94c73099f0fDan Williams	unsigned long flags;
355fd18388bc5820b3e7807302ac18e8e7de83c9f4cEdmund Nadolski	unsigned long timeleft;
356312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams	u16 tag;
357312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams
358312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams	spin_lock_irqsave(&ihost->scic_lock, flags);
359312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams	tag = isci_alloc_tag(ihost);
360312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams	spin_unlock_irqrestore(&ihost->scic_lock, flags);
361312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams
362312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams	if (tag == SCI_CONTROLLER_INVALID_IO_TAG)
363312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams		return ret;
3646f231dda68080759f1aed3769896e94c73099f0fDan Williams
3656f231dda68080759f1aed3769896e94c73099f0fDan Williams	/* sanity check, return TMF_RESP_FUNC_FAILED
3666f231dda68080759f1aed3769896e94c73099f0fDan Williams	 * if the device is not there and ready.
3676f231dda68080759f1aed3769896e94c73099f0fDan Williams	 */
36878a6f06e0e82125787d7aa308fe28c2c8381540cDan Williams	if (!idev ||
36978a6f06e0e82125787d7aa308fe28c2c8381540cDan Williams	    (!test_bit(IDEV_IO_READY, &idev->flags) &&
37078a6f06e0e82125787d7aa308fe28c2c8381540cDan Williams	     !test_bit(IDEV_IO_NCQERROR, &idev->flags))) {
3710d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams		dev_dbg(&ihost->pdev->dev,
37278a6f06e0e82125787d7aa308fe28c2c8381540cDan Williams			"%s: idev = %p not ready (%#lx)\n",
3736f231dda68080759f1aed3769896e94c73099f0fDan Williams			__func__,
37478a6f06e0e82125787d7aa308fe28c2c8381540cDan Williams			idev, idev ? idev->flags : 0);
375312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams		goto err_tci;
3766f231dda68080759f1aed3769896e94c73099f0fDan Williams	} else
3770d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams		dev_dbg(&ihost->pdev->dev,
37878a6f06e0e82125787d7aa308fe28c2c8381540cDan Williams			"%s: idev = %p\n",
37978a6f06e0e82125787d7aa308fe28c2c8381540cDan Williams			__func__, idev);
3806f231dda68080759f1aed3769896e94c73099f0fDan Williams
3816f231dda68080759f1aed3769896e94c73099f0fDan Williams	/* Assign the pointer to the TMF's completion kernel wait structure. */
3826f231dda68080759f1aed3769896e94c73099f0fDan Williams	tmf->complete = &completion;
383b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	tmf->status = SCI_FAILURE_TIMEOUT;
3846f231dda68080759f1aed3769896e94c73099f0fDan Williams
38578a6f06e0e82125787d7aa308fe28c2c8381540cDan Williams	ireq = isci_task_request_build(ihost, idev, tag, tmf);
386312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams	if (!ireq)
387312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams		goto err_tci;
3886f231dda68080759f1aed3769896e94c73099f0fDan Williams
3890d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams	spin_lock_irqsave(&ihost->scic_lock, flags);
3906f231dda68080759f1aed3769896e94c73099f0fDan Williams
3916f231dda68080759f1aed3769896e94c73099f0fDan Williams	/* start the TMF io. */
39289a7301f21fb00e753089671eb9e4132aab8ea08Dan Williams	status = sci_controller_start_task(ihost, idev, ireq);
3936f231dda68080759f1aed3769896e94c73099f0fDan Williams
394467e855a0331f619f41fbf7391bc29ec0ca923a0Bartosz Barcinski	if (status != SCI_TASK_SUCCESS) {
395a8a0a133b03c6863d0f77229d19befca4de905faDan Williams		dev_dbg(&ihost->pdev->dev,
3966f231dda68080759f1aed3769896e94c73099f0fDan Williams			 "%s: start_io failed - status = 0x%x, request = %p\n",
3976f231dda68080759f1aed3769896e94c73099f0fDan Williams			 __func__,
3986f231dda68080759f1aed3769896e94c73099f0fDan Williams			 status,
3990d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams			 ireq);
4000d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams		spin_unlock_irqrestore(&ihost->scic_lock, flags);
401db0562509800a2d4cb5cb14a66413c30484f165cDan Williams		goto err_tci;
4026f231dda68080759f1aed3769896e94c73099f0fDan Williams	}
4036f231dda68080759f1aed3769896e94c73099f0fDan Williams
4046f231dda68080759f1aed3769896e94c73099f0fDan Williams	if (tmf->cb_state_func != NULL)
4056f231dda68080759f1aed3769896e94c73099f0fDan Williams		tmf->cb_state_func(isci_tmf_started, tmf, tmf->cb_data);
4066f231dda68080759f1aed3769896e94c73099f0fDan Williams
4070d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams	isci_request_change_state(ireq, started);
4086f231dda68080759f1aed3769896e94c73099f0fDan Williams
4096f231dda68080759f1aed3769896e94c73099f0fDan Williams	/* add the request to the remote device request list. */
41078a6f06e0e82125787d7aa308fe28c2c8381540cDan Williams	list_add(&ireq->dev_node, &idev->reqs_in_process);
4116f231dda68080759f1aed3769896e94c73099f0fDan Williams
4120d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams	spin_unlock_irqrestore(&ihost->scic_lock, flags);
4136f231dda68080759f1aed3769896e94c73099f0fDan Williams
4146f231dda68080759f1aed3769896e94c73099f0fDan Williams	/* Wait for the TMF to complete, or a timeout. */
415fd18388bc5820b3e7807302ac18e8e7de83c9f4cEdmund Nadolski	timeleft = wait_for_completion_timeout(&completion,
416086a0dabc5bf154e13604a6d71e2d051207f9718Dan Williams					       msecs_to_jiffies(timeout_ms));
417fd18388bc5820b3e7807302ac18e8e7de83c9f4cEdmund Nadolski
418fd18388bc5820b3e7807302ac18e8e7de83c9f4cEdmund Nadolski	if (timeleft == 0) {
419b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		/* The TMF did not complete - this could be because
420b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		 * of an unplug.  Terminate the TMF request now.
421b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		 */
4220d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams		spin_lock_irqsave(&ihost->scic_lock, flags);
423fd18388bc5820b3e7807302ac18e8e7de83c9f4cEdmund Nadolski
424fd18388bc5820b3e7807302ac18e8e7de83c9f4cEdmund Nadolski		if (tmf->cb_state_func != NULL)
425b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			tmf->cb_state_func(isci_tmf_timed_out, tmf,
426b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin					   tmf->cb_data);
427fd18388bc5820b3e7807302ac18e8e7de83c9f4cEdmund Nadolski
428b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		sci_controller_terminate_request(ihost, idev, ireq);
429fd18388bc5820b3e7807302ac18e8e7de83c9f4cEdmund Nadolski
4300d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams		spin_unlock_irqrestore(&ihost->scic_lock, flags);
431086a0dabc5bf154e13604a6d71e2d051207f9718Dan Williams
432b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		timeleft = wait_for_completion_timeout(
433b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			&completion,
434b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			msecs_to_jiffies(ISCI_TERMINATION_TIMEOUT_MSEC));
435b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin
436b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		if (!timeleft) {
437b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			/* Strange condition - the termination of the TMF
438b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			 * request timed-out.
439b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			 */
440b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			spin_lock_irqsave(&ihost->scic_lock, flags);
441b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin
442b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			/* If the TMF status has not changed, kill it. */
443b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			if (tmf->status == SCI_FAILURE_TIMEOUT)
444b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin				isci_request_mark_zombie(ihost, ireq);
445b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin
446b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			spin_unlock_irqrestore(&ihost->scic_lock, flags);
447b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		}
448fd18388bc5820b3e7807302ac18e8e7de83c9f4cEdmund Nadolski	}
4496f231dda68080759f1aed3769896e94c73099f0fDan Williams
45027234ab44f97d85bab062a9d18aaff99addd267dMaciej Trela	isci_print_tmf(ihost, tmf);
4516f231dda68080759f1aed3769896e94c73099f0fDan Williams
4526f231dda68080759f1aed3769896e94c73099f0fDan Williams	if (tmf->status == SCI_SUCCESS)
4536f231dda68080759f1aed3769896e94c73099f0fDan Williams		ret =  TMF_RESP_FUNC_COMPLETE;
4546f231dda68080759f1aed3769896e94c73099f0fDan Williams	else if (tmf->status == SCI_FAILURE_IO_RESPONSE_VALID) {
4550d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams		dev_dbg(&ihost->pdev->dev,
4566f231dda68080759f1aed3769896e94c73099f0fDan Williams			"%s: tmf.status == "
4576f231dda68080759f1aed3769896e94c73099f0fDan Williams			"SCI_FAILURE_IO_RESPONSE_VALID\n",
4586f231dda68080759f1aed3769896e94c73099f0fDan Williams			__func__);
4596f231dda68080759f1aed3769896e94c73099f0fDan Williams		ret =  TMF_RESP_FUNC_COMPLETE;
4606f231dda68080759f1aed3769896e94c73099f0fDan Williams	}
4616f231dda68080759f1aed3769896e94c73099f0fDan Williams	/* Else - leave the default "failed" status alone. */
4626f231dda68080759f1aed3769896e94c73099f0fDan Williams
4630d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams	dev_dbg(&ihost->pdev->dev,
4646f231dda68080759f1aed3769896e94c73099f0fDan Williams		"%s: completed request = %p\n",
4656f231dda68080759f1aed3769896e94c73099f0fDan Williams		__func__,
4660d0cf14c9bd2943ed5afd15df459f564d85eacdeDan Williams		ireq);
4676f231dda68080759f1aed3769896e94c73099f0fDan Williams
4686f231dda68080759f1aed3769896e94c73099f0fDan Williams	return ret;
469312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams
470312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams err_tci:
471312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams	spin_lock_irqsave(&ihost->scic_lock, flags);
472312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams	isci_tci_free(ihost, ISCI_TAG_TCI(tag));
473312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams	spin_unlock_irqrestore(&ihost->scic_lock, flags);
474312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams
475312e0c2455c18716cf640d4336dcb1e9e5053818Dan Williams	return ret;
4766f231dda68080759f1aed3769896e94c73099f0fDan Williams}
4776f231dda68080759f1aed3769896e94c73099f0fDan Williams
47816ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williamsstatic void isci_task_build_tmf(struct isci_tmf *tmf,
47916ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williams				enum isci_tmf_function_codes code,
48016ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williams				void (*tmf_sent_cb)(enum isci_tmf_cb_state,
48116ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williams						    struct isci_tmf *,
48216ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williams						    void *),
48316ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williams				void *cb_data)
4846f231dda68080759f1aed3769896e94c73099f0fDan Williams{
4856f231dda68080759f1aed3769896e94c73099f0fDan Williams	memset(tmf, 0, sizeof(*tmf));
4866f231dda68080759f1aed3769896e94c73099f0fDan Williams
4876f231dda68080759f1aed3769896e94c73099f0fDan Williams	tmf->tmf_code      = code;
4886f231dda68080759f1aed3769896e94c73099f0fDan Williams	tmf->cb_state_func = tmf_sent_cb;
489c3f42feb0c3d20dc7007336e7de949408b93afefJeff Skirvin	tmf->cb_data       = cb_data;
490c3f42feb0c3d20dc7007336e7de949408b93afefJeff Skirvin}
4911fad9e934a43407c1ba397b1b6b8882aa8a2cafdJeff Skirvin
49216ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williamsstatic void isci_task_build_abort_task_tmf(struct isci_tmf *tmf,
49316ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williams					   enum isci_tmf_function_codes code,
49416ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williams					   void (*tmf_sent_cb)(enum isci_tmf_cb_state,
49516ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williams							       struct isci_tmf *,
49616ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williams							       void *),
49716ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williams					   struct isci_request *old_request)
498c3f42feb0c3d20dc7007336e7de949408b93afefJeff Skirvin{
49916ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williams	isci_task_build_tmf(tmf, code, tmf_sent_cb, old_request);
500c3f42feb0c3d20dc7007336e7de949408b93afefJeff Skirvin	tmf->io_tag = old_request->io_tag;
5016f231dda68080759f1aed3769896e94c73099f0fDan Williams}
5026f231dda68080759f1aed3769896e94c73099f0fDan Williams
5036f231dda68080759f1aed3769896e94c73099f0fDan Williams/**
5046f231dda68080759f1aed3769896e94c73099f0fDan Williams * isci_task_validate_request_to_abort() - This function checks the given I/O
5056f231dda68080759f1aed3769896e94c73099f0fDan Williams *    against the "started" state.  If the request is still "started", it's
5066f231dda68080759f1aed3769896e94c73099f0fDan Williams *    state is changed to aborted. NOTE: isci_host->scic_lock MUST BE HELD
5076f231dda68080759f1aed3769896e94c73099f0fDan Williams *    BEFORE CALLING THIS FUNCTION.
5086f231dda68080759f1aed3769896e94c73099f0fDan Williams * @isci_request: This parameter specifies the request object to control.
5096f231dda68080759f1aed3769896e94c73099f0fDan Williams * @isci_host: This parameter specifies the ISCI host object
5106f231dda68080759f1aed3769896e94c73099f0fDan Williams * @isci_device: This is the device to which the request is pending.
5116f231dda68080759f1aed3769896e94c73099f0fDan Williams * @aborted_io_completion: This is a completion structure that will be added to
5126f231dda68080759f1aed3769896e94c73099f0fDan Williams *    the request in case it is changed to aborting; this completion is
5136f231dda68080759f1aed3769896e94c73099f0fDan Williams *    triggered when the request is fully completed.
5146f231dda68080759f1aed3769896e94c73099f0fDan Williams *
5156f231dda68080759f1aed3769896e94c73099f0fDan Williams * Either "started" on successful change of the task status to "aborted", or
5166f231dda68080759f1aed3769896e94c73099f0fDan Williams * "unallocated" if the task cannot be controlled.
5176f231dda68080759f1aed3769896e94c73099f0fDan Williams */
5186f231dda68080759f1aed3769896e94c73099f0fDan Williamsstatic enum isci_request_status isci_task_validate_request_to_abort(
5196f231dda68080759f1aed3769896e94c73099f0fDan Williams	struct isci_request *isci_request,
5206f231dda68080759f1aed3769896e94c73099f0fDan Williams	struct isci_host *isci_host,
5216f231dda68080759f1aed3769896e94c73099f0fDan Williams	struct isci_remote_device *isci_device,
5226f231dda68080759f1aed3769896e94c73099f0fDan Williams	struct completion *aborted_io_completion)
5236f231dda68080759f1aed3769896e94c73099f0fDan Williams{
5246f231dda68080759f1aed3769896e94c73099f0fDan Williams	enum isci_request_status old_state = unallocated;
5256f231dda68080759f1aed3769896e94c73099f0fDan Williams
5266f231dda68080759f1aed3769896e94c73099f0fDan Williams	/* Only abort the task if it's in the
5276f231dda68080759f1aed3769896e94c73099f0fDan Williams	 *  device's request_in_process list
5286f231dda68080759f1aed3769896e94c73099f0fDan Williams	 */
5296f231dda68080759f1aed3769896e94c73099f0fDan Williams	if (isci_request && !list_empty(&isci_request->dev_node)) {
5306f231dda68080759f1aed3769896e94c73099f0fDan Williams		old_state = isci_request_change_started_to_aborted(
5316f231dda68080759f1aed3769896e94c73099f0fDan Williams			isci_request, aborted_io_completion);
5326f231dda68080759f1aed3769896e94c73099f0fDan Williams
5336f231dda68080759f1aed3769896e94c73099f0fDan Williams	}
5346f231dda68080759f1aed3769896e94c73099f0fDan Williams
5356f231dda68080759f1aed3769896e94c73099f0fDan Williams	return old_state;
5366f231dda68080759f1aed3769896e94c73099f0fDan Williams}
5376f231dda68080759f1aed3769896e94c73099f0fDan Williams
538d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvinstatic int isci_request_is_dealloc_managed(enum isci_request_status stat)
539d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin{
540d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin	switch (stat) {
541d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin	case aborted:
542d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin	case aborting:
543d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin	case terminating:
544d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin	case completed:
545d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin	case dead:
546d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin		return true;
547d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin	default:
548d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin		return false;
549d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin	}
550d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin}
551d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin
5526f231dda68080759f1aed3769896e94c73099f0fDan Williams/**
5536f231dda68080759f1aed3769896e94c73099f0fDan Williams * isci_terminate_request_core() - This function will terminate the given
5546f231dda68080759f1aed3769896e94c73099f0fDan Williams *    request, and wait for it to complete.  This function must only be called
5556f231dda68080759f1aed3769896e94c73099f0fDan Williams *    from a thread that can wait.  Note that the request is terminated and
5566f231dda68080759f1aed3769896e94c73099f0fDan Williams *    completed (back to the host, if started there).
557d9dcb4ba791de2a06b19ac47cd61601cf3d4e208Dan Williams * @ihost: This SCU.
55878a6f06e0e82125787d7aa308fe28c2c8381540cDan Williams * @idev: The target.
5596f231dda68080759f1aed3769896e94c73099f0fDan Williams * @isci_request: The I/O request to be terminated.
5606f231dda68080759f1aed3769896e94c73099f0fDan Williams *
5616f231dda68080759f1aed3769896e94c73099f0fDan Williams */
562d9dcb4ba791de2a06b19ac47cd61601cf3d4e208Dan Williamsstatic void isci_terminate_request_core(struct isci_host *ihost,
563d9dcb4ba791de2a06b19ac47cd61601cf3d4e208Dan Williams					struct isci_remote_device *idev,
564d9dcb4ba791de2a06b19ac47cd61601cf3d4e208Dan Williams					struct isci_request *isci_request)
5656f231dda68080759f1aed3769896e94c73099f0fDan Williams{
566cbb65c665b341e560b7a3b37cc616376031b3ee5Jeff Skirvin	enum sci_status status      = SCI_SUCCESS;
5676f231dda68080759f1aed3769896e94c73099f0fDan Williams	bool was_terminated         = false;
5686f231dda68080759f1aed3769896e94c73099f0fDan Williams	bool needs_cleanup_handling = false;
56977c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin	unsigned long     flags;
57077c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin	unsigned long     termination_completed = 1;
57177c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin	struct completion *io_request_completion;
5726f231dda68080759f1aed3769896e94c73099f0fDan Williams
573d9dcb4ba791de2a06b19ac47cd61601cf3d4e208Dan Williams	dev_dbg(&ihost->pdev->dev,
5746f231dda68080759f1aed3769896e94c73099f0fDan Williams		"%s: device = %p; request = %p\n",
57578a6f06e0e82125787d7aa308fe28c2c8381540cDan Williams		__func__, idev, isci_request);
5766f231dda68080759f1aed3769896e94c73099f0fDan Williams
577d9dcb4ba791de2a06b19ac47cd61601cf3d4e208Dan Williams	spin_lock_irqsave(&ihost->scic_lock, flags);
5784dc043c41037fc6e369270daaa626465a8766565Jeff Skirvin
57977c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin	io_request_completion = isci_request->io_request_completion;
58077c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin
5814dc043c41037fc6e369270daaa626465a8766565Jeff Skirvin	/* Note that we are not going to control
58238d8879baeb61b6946052739e7c03fa79b3a57f0Dan Williams	 * the target to abort the request.
58338d8879baeb61b6946052739e7c03fa79b3a57f0Dan Williams	 */
58438d8879baeb61b6946052739e7c03fa79b3a57f0Dan Williams	set_bit(IREQ_COMPLETE_IN_TARGET, &isci_request->flags);
5854dc043c41037fc6e369270daaa626465a8766565Jeff Skirvin
5866f231dda68080759f1aed3769896e94c73099f0fDan Williams	/* Make sure the request wasn't just sitting around signalling
5876f231dda68080759f1aed3769896e94c73099f0fDan Williams	 * device condition (if the request handle is NULL, then the
5886f231dda68080759f1aed3769896e94c73099f0fDan Williams	 * request completed but needed additional handling here).
5896f231dda68080759f1aed3769896e94c73099f0fDan Williams	 */
59038d8879baeb61b6946052739e7c03fa79b3a57f0Dan Williams	if (!test_bit(IREQ_TERMINATED, &isci_request->flags)) {
5916f231dda68080759f1aed3769896e94c73099f0fDan Williams		was_terminated = true;
592cbb65c665b341e560b7a3b37cc616376031b3ee5Jeff Skirvin		needs_cleanup_handling = true;
59389a7301f21fb00e753089671eb9e4132aab8ea08Dan Williams		status = sci_controller_terminate_request(ihost,
594d9dcb4ba791de2a06b19ac47cd61601cf3d4e208Dan Williams							   idev,
595d9dcb4ba791de2a06b19ac47cd61601cf3d4e208Dan Williams							   isci_request);
5966f231dda68080759f1aed3769896e94c73099f0fDan Williams	}
597d9dcb4ba791de2a06b19ac47cd61601cf3d4e208Dan Williams	spin_unlock_irqrestore(&ihost->scic_lock, flags);
5986f231dda68080759f1aed3769896e94c73099f0fDan Williams
5996f231dda68080759f1aed3769896e94c73099f0fDan Williams	/*
6006f231dda68080759f1aed3769896e94c73099f0fDan Williams	 * The only time the request to terminate will
6016f231dda68080759f1aed3769896e94c73099f0fDan Williams	 * fail is when the io request is completed and
6026f231dda68080759f1aed3769896e94c73099f0fDan Williams	 * being aborted.
6036f231dda68080759f1aed3769896e94c73099f0fDan Williams	 */
6044dc043c41037fc6e369270daaa626465a8766565Jeff Skirvin	if (status != SCI_SUCCESS) {
605a8a0a133b03c6863d0f77229d19befca4de905faDan Williams		dev_dbg(&ihost->pdev->dev,
60689a7301f21fb00e753089671eb9e4132aab8ea08Dan Williams			"%s: sci_controller_terminate_request"
6076f231dda68080759f1aed3769896e94c73099f0fDan Williams			" returned = 0x%x\n",
60877c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin			__func__, status);
60977c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin
6104dc043c41037fc6e369270daaa626465a8766565Jeff Skirvin		isci_request->io_request_completion = NULL;
6114dc043c41037fc6e369270daaa626465a8766565Jeff Skirvin
6124dc043c41037fc6e369270daaa626465a8766565Jeff Skirvin	} else {
6136f231dda68080759f1aed3769896e94c73099f0fDan Williams		if (was_terminated) {
614d9dcb4ba791de2a06b19ac47cd61601cf3d4e208Dan Williams			dev_dbg(&ihost->pdev->dev,
61577c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin				"%s: before completion wait (%p/%p)\n",
61677c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin				__func__, isci_request, io_request_completion);
6176f231dda68080759f1aed3769896e94c73099f0fDan Williams
6186f231dda68080759f1aed3769896e94c73099f0fDan Williams			/* Wait here for the request to complete. */
61977c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin			termination_completed
6204dc043c41037fc6e369270daaa626465a8766565Jeff Skirvin				= wait_for_completion_timeout(
62177c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin				   io_request_completion,
622b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin				   msecs_to_jiffies(ISCI_TERMINATION_TIMEOUT_MSEC));
6234dc043c41037fc6e369270daaa626465a8766565Jeff Skirvin
62477c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin			if (!termination_completed) {
62577c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin
62677c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin				/* The request to terminate has timed out.  */
627b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin				spin_lock_irqsave(&ihost->scic_lock, flags);
62877c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin
62977c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin				/* Check for state changes. */
630b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin				if (!test_bit(IREQ_TERMINATED,
631b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin					      &isci_request->flags)) {
63277c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin
63377c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin					/* The best we can do is to have the
63477c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin					 * request die a silent death if it
63577c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin					 * ever really completes.
63677c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin					 */
637b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin					isci_request_mark_zombie(ihost,
638b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin								 isci_request);
639b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin					needs_cleanup_handling = true;
64077c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin				} else
64177c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin					termination_completed = 1;
64277c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin
643d9dcb4ba791de2a06b19ac47cd61601cf3d4e208Dan Williams				spin_unlock_irqrestore(&ihost->scic_lock,
64477c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin						       flags);
6454dc043c41037fc6e369270daaa626465a8766565Jeff Skirvin
64677c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin				if (!termination_completed) {
6474dc043c41037fc6e369270daaa626465a8766565Jeff Skirvin
648a8a0a133b03c6863d0f77229d19befca4de905faDan Williams					dev_dbg(&ihost->pdev->dev,
64977c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin						"%s: *** Timeout waiting for "
65077c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin						"termination(%p/%p)\n",
65177c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin						__func__, io_request_completion,
65277c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin						isci_request);
6534dc043c41037fc6e369270daaa626465a8766565Jeff Skirvin
65477c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin					/* The request can no longer be referenced
65577c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin					 * safely since it may go away if the
65677c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin					 * termination every really does complete.
65777c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin					 */
65877c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin					isci_request = NULL;
65977c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin				}
66077c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin			}
66177c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin			if (termination_completed)
662d9dcb4ba791de2a06b19ac47cd61601cf3d4e208Dan Williams				dev_dbg(&ihost->pdev->dev,
66377c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin					"%s: after completion wait (%p/%p)\n",
66477c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin					__func__, isci_request, io_request_completion);
6654dc043c41037fc6e369270daaa626465a8766565Jeff Skirvin		}
6664dc043c41037fc6e369270daaa626465a8766565Jeff Skirvin
66777c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin		if (termination_completed) {
668cbb65c665b341e560b7a3b37cc616376031b3ee5Jeff Skirvin
66977c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin			isci_request->io_request_completion = NULL;
6706f231dda68080759f1aed3769896e94c73099f0fDan Williams
67177c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin			/* Peek at the status of the request.  This will tell
67277c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin			 * us if there was special handling on the request such that it
67377c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin			 * needs to be detached and freed here.
67477c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin			 */
67577c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin			spin_lock_irqsave(&isci_request->state_lock, flags);
676d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin
677d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin			needs_cleanup_handling
678d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin				= isci_request_is_dealloc_managed(
679d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin					isci_request->status);
680d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin
68177c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin			spin_unlock_irqrestore(&isci_request->state_lock, flags);
6826f231dda68080759f1aed3769896e94c73099f0fDan Williams
68377c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin		}
684db49c2d037d50dfc67b29a4e013d6250ca97c3aaJeff Skirvin		if (needs_cleanup_handling) {
685db49c2d037d50dfc67b29a4e013d6250ca97c3aaJeff Skirvin
686db49c2d037d50dfc67b29a4e013d6250ca97c3aaJeff Skirvin			dev_dbg(&ihost->pdev->dev,
687db49c2d037d50dfc67b29a4e013d6250ca97c3aaJeff Skirvin				"%s: cleanup isci_device=%p, request=%p\n",
688db49c2d037d50dfc67b29a4e013d6250ca97c3aaJeff Skirvin				__func__, idev, isci_request);
689db49c2d037d50dfc67b29a4e013d6250ca97c3aaJeff Skirvin
690db49c2d037d50dfc67b29a4e013d6250ca97c3aaJeff Skirvin			if (isci_request != NULL) {
691db49c2d037d50dfc67b29a4e013d6250ca97c3aaJeff Skirvin				spin_lock_irqsave(&ihost->scic_lock, flags);
692db49c2d037d50dfc67b29a4e013d6250ca97c3aaJeff Skirvin				isci_free_tag(ihost, isci_request->io_tag);
693db49c2d037d50dfc67b29a4e013d6250ca97c3aaJeff Skirvin				isci_request_change_state(isci_request, unallocated);
694db49c2d037d50dfc67b29a4e013d6250ca97c3aaJeff Skirvin				list_del_init(&isci_request->dev_node);
695db49c2d037d50dfc67b29a4e013d6250ca97c3aaJeff Skirvin				spin_unlock_irqrestore(&ihost->scic_lock, flags);
696db49c2d037d50dfc67b29a4e013d6250ca97c3aaJeff Skirvin			}
697db49c2d037d50dfc67b29a4e013d6250ca97c3aaJeff Skirvin		}
698a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin	}
6996f231dda68080759f1aed3769896e94c73099f0fDan Williams}
7006f231dda68080759f1aed3769896e94c73099f0fDan Williams
7016f231dda68080759f1aed3769896e94c73099f0fDan Williams/**
7026f231dda68080759f1aed3769896e94c73099f0fDan Williams * isci_terminate_pending_requests() - This function will change the all of the
7036f231dda68080759f1aed3769896e94c73099f0fDan Williams *    requests on the given device's state to "aborting", will terminate the
7046f231dda68080759f1aed3769896e94c73099f0fDan Williams *    requests, and wait for them to complete.  This function must only be
7056f231dda68080759f1aed3769896e94c73099f0fDan Williams *    called from a thread that can wait.  Note that the requests are all
7066f231dda68080759f1aed3769896e94c73099f0fDan Williams *    terminated and completed (back to the host, if started there).
7076f231dda68080759f1aed3769896e94c73099f0fDan Williams * @isci_host: This parameter specifies SCU.
70878a6f06e0e82125787d7aa308fe28c2c8381540cDan Williams * @idev: This parameter specifies the target.
7096f231dda68080759f1aed3769896e94c73099f0fDan Williams *
7106f231dda68080759f1aed3769896e94c73099f0fDan Williams */
711980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williamsvoid isci_terminate_pending_requests(struct isci_host *ihost,
712980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams				     struct isci_remote_device *idev)
7136f231dda68080759f1aed3769896e94c73099f0fDan Williams{
714980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams	struct completion request_completion;
71577c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin	enum isci_request_status old_state;
716980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams	unsigned long flags;
717980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams	LIST_HEAD(list);
7186f231dda68080759f1aed3769896e94c73099f0fDan Williams
719980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams	spin_lock_irqsave(&ihost->scic_lock, flags);
720980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams	list_splice_init(&idev->reqs_in_process, &list);
7216f231dda68080759f1aed3769896e94c73099f0fDan Williams
722980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams	/* assumes that isci_terminate_request_core deletes from the list */
723980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams	while (!list_empty(&list)) {
724980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		struct isci_request *ireq = list_entry(list.next, typeof(*ireq), dev_node);
7256f231dda68080759f1aed3769896e94c73099f0fDan Williams
726980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		/* Change state to "terminating" if it is currently
727980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * "started".
728980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 */
729980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		old_state = isci_request_change_started_to_newstate(ireq,
730980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams								    &request_completion,
731980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams								    terminating);
732980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		switch (old_state) {
733980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		case started:
734980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		case completed:
735980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		case aborting:
736980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams			break;
737980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		default:
738980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams			/* termination in progress, or otherwise dispositioned.
739980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams			 * We know the request was on 'list' so should be safe
740980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams			 * to move it back to reqs_in_process
741980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams			 */
742980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams			list_move(&ireq->dev_node, &idev->reqs_in_process);
743980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams			ireq = NULL;
744980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams			break;
745980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		}
7464dc043c41037fc6e369270daaa626465a8766565Jeff Skirvin
747980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		if (!ireq)
748980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams			continue;
749980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		spin_unlock_irqrestore(&ihost->scic_lock, flags);
75077c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin
751980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		init_completion(&request_completion);
75277c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin
753980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		dev_dbg(&ihost->pdev->dev,
754980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams			 "%s: idev=%p request=%p; task=%p old_state=%d\n",
755980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams			 __func__, idev, ireq,
7563b34c169f8197e02529fa3ec703703c2ce418c57Jeff Skirvin			(!test_bit(IREQ_TMF, &ireq->flags)
7573b34c169f8197e02529fa3ec703703c2ce418c57Jeff Skirvin				? isci_request_access_task(ireq)
7583b34c169f8197e02529fa3ec703703c2ce418c57Jeff Skirvin				: NULL),
759980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams			old_state);
760980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams
761980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		/* If the old_state is started:
762980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * This request was not already being aborted. If it had been,
763980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * then the aborting I/O (ie. the TMF request) would not be in
764980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * the aborting state, and thus would be terminated here.  Note
765980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * that since the TMF completion's call to the kernel function
766980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * "complete()" does not happen until the pending I/O request
767980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * terminate fully completes, we do not have to implement a
768980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * special wait here for already aborting requests - the
769980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * termination of the TMF request will force the request
770980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * to finish it's already started terminate.
771980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 *
772980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * If old_state == completed:
773980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * This request completed from the SCU hardware perspective
774980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * and now just needs cleaning up in terms of freeing the
775980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * request and potentially calling up to libsas.
776980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 *
777980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * If old_state == aborting:
778980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * This request has already gone through a TMF timeout, but may
779980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 * not have been terminated; needs cleaning up at least.
780980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		 */
781980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		isci_terminate_request_core(ihost, idev, ireq);
782980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams		spin_lock_irqsave(&ihost->scic_lock, flags);
7834dc043c41037fc6e369270daaa626465a8766565Jeff Skirvin	}
784980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams	spin_unlock_irqrestore(&ihost->scic_lock, flags);
7856f231dda68080759f1aed3769896e94c73099f0fDan Williams}
7866f231dda68080759f1aed3769896e94c73099f0fDan Williams
7876f231dda68080759f1aed3769896e94c73099f0fDan Williams/**
7886f231dda68080759f1aed3769896e94c73099f0fDan Williams * isci_task_send_lu_reset_sas() - This function is called by of the SAS Domain
7896f231dda68080759f1aed3769896e94c73099f0fDan Williams *    Template functions.
7906f231dda68080759f1aed3769896e94c73099f0fDan Williams * @lun: This parameter specifies the lun to be reset.
7916f231dda68080759f1aed3769896e94c73099f0fDan Williams *
7926f231dda68080759f1aed3769896e94c73099f0fDan Williams * status, zero indicates success.
7936f231dda68080759f1aed3769896e94c73099f0fDan Williams */
7946f231dda68080759f1aed3769896e94c73099f0fDan Williamsstatic int isci_task_send_lu_reset_sas(
7956f231dda68080759f1aed3769896e94c73099f0fDan Williams	struct isci_host *isci_host,
7966f231dda68080759f1aed3769896e94c73099f0fDan Williams	struct isci_remote_device *isci_device,
7976f231dda68080759f1aed3769896e94c73099f0fDan Williams	u8 *lun)
7986f231dda68080759f1aed3769896e94c73099f0fDan Williams{
7996f231dda68080759f1aed3769896e94c73099f0fDan Williams	struct isci_tmf tmf;
8006f231dda68080759f1aed3769896e94c73099f0fDan Williams	int ret = TMF_RESP_FUNC_FAILED;
8016f231dda68080759f1aed3769896e94c73099f0fDan Williams
8026f231dda68080759f1aed3769896e94c73099f0fDan Williams	dev_dbg(&isci_host->pdev->dev,
8036f231dda68080759f1aed3769896e94c73099f0fDan Williams		"%s: isci_host = %p, isci_device = %p\n",
8046f231dda68080759f1aed3769896e94c73099f0fDan Williams		__func__, isci_host, isci_device);
8056f231dda68080759f1aed3769896e94c73099f0fDan Williams	/* Send the LUN reset to the target.  By the time the call returns,
8066f231dda68080759f1aed3769896e94c73099f0fDan Williams	 * the TMF has fully exected in the target (in which case the return
8076f231dda68080759f1aed3769896e94c73099f0fDan Williams	 * value is "TMF_RESP_FUNC_COMPLETE", or the request timed-out (or
8086f231dda68080759f1aed3769896e94c73099f0fDan Williams	 * was otherwise unable to be executed ("TMF_RESP_FUNC_FAILED").
8096f231dda68080759f1aed3769896e94c73099f0fDan Williams	 */
810209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	isci_task_build_tmf(&tmf, isci_tmf_ssp_lun_reset, NULL, NULL);
8116f231dda68080759f1aed3769896e94c73099f0fDan Williams
8126f231dda68080759f1aed3769896e94c73099f0fDan Williams	#define ISCI_LU_RESET_TIMEOUT_MS 2000 /* 2 second timeout. */
813209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	ret = isci_task_execute_tmf(isci_host, isci_device, &tmf, ISCI_LU_RESET_TIMEOUT_MS);
8146f231dda68080759f1aed3769896e94c73099f0fDan Williams
8156f231dda68080759f1aed3769896e94c73099f0fDan Williams	if (ret == TMF_RESP_FUNC_COMPLETE)
8166f231dda68080759f1aed3769896e94c73099f0fDan Williams		dev_dbg(&isci_host->pdev->dev,
8176f231dda68080759f1aed3769896e94c73099f0fDan Williams			"%s: %p: TMF_LU_RESET passed\n",
8186f231dda68080759f1aed3769896e94c73099f0fDan Williams			__func__, isci_device);
8196f231dda68080759f1aed3769896e94c73099f0fDan Williams	else
8206f231dda68080759f1aed3769896e94c73099f0fDan Williams		dev_dbg(&isci_host->pdev->dev,
8216f231dda68080759f1aed3769896e94c73099f0fDan Williams			"%s: %p: TMF_LU_RESET failed (%x)\n",
8226f231dda68080759f1aed3769896e94c73099f0fDan Williams			__func__, isci_device, ret);
8236f231dda68080759f1aed3769896e94c73099f0fDan Williams
8246f231dda68080759f1aed3769896e94c73099f0fDan Williams	return ret;
8256f231dda68080759f1aed3769896e94c73099f0fDan Williams}
8266f231dda68080759f1aed3769896e94c73099f0fDan Williams
82743a5ab151f0268459c4368292c2ddb2266b8f243Dan Williamsint isci_task_lu_reset(struct domain_device *dev, u8 *lun)
82816ba77091b44af28b3ff3318b4a2aa4fbf7d4c24Dan Williams{
82943a5ab151f0268459c4368292c2ddb2266b8f243Dan Williams	struct isci_host *isci_host = dev_to_ihost(dev);
830209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	struct isci_remote_device *isci_device;
831209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	unsigned long flags;
8326f231dda68080759f1aed3769896e94c73099f0fDan Williams	int ret;
8336f231dda68080759f1aed3769896e94c73099f0fDan Williams
834209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	spin_lock_irqsave(&isci_host->scic_lock, flags);
83543a5ab151f0268459c4368292c2ddb2266b8f243Dan Williams	isci_device = isci_lookup_device(dev);
836209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	spin_unlock_irqrestore(&isci_host->scic_lock, flags);
8376f231dda68080759f1aed3769896e94c73099f0fDan Williams
8384393aa4e6b9517a666f0ef6b774fd421a9dc4c68Dan Williams	dev_dbg(&isci_host->pdev->dev,
8394393aa4e6b9517a666f0ef6b774fd421a9dc4c68Dan Williams		"%s: domain_device=%p, isci_host=%p; isci_device=%p\n",
84043a5ab151f0268459c4368292c2ddb2266b8f243Dan Williams		 __func__, dev, isci_host, isci_device);
8416f231dda68080759f1aed3769896e94c73099f0fDan Williams
84298145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin	if (!isci_device) {
84398145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		/* If the device is gone, stop the escalations. */
84498145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		dev_dbg(&isci_host->pdev->dev, "%s: No dev\n", __func__);
8456f231dda68080759f1aed3769896e94c73099f0fDan Williams
84698145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		ret = TMF_RESP_FUNC_COMPLETE;
847209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams		goto out;
8486f231dda68080759f1aed3769896e94c73099f0fDan Williams	}
8496f231dda68080759f1aed3769896e94c73099f0fDan Williams
8506f231dda68080759f1aed3769896e94c73099f0fDan Williams	/* Send the task management part of the reset. */
85143a5ab151f0268459c4368292c2ddb2266b8f243Dan Williams	if (dev_is_sata(dev)) {
85243a5ab151f0268459c4368292c2ddb2266b8f243Dan Williams		sas_ata_schedule_reset(dev);
85343a5ab151f0268459c4368292c2ddb2266b8f243Dan Williams		ret = TMF_RESP_FUNC_COMPLETE;
8546f231dda68080759f1aed3769896e94c73099f0fDan Williams	} else
8556f231dda68080759f1aed3769896e94c73099f0fDan Williams		ret = isci_task_send_lu_reset_sas(isci_host, isci_device, lun);
8566f231dda68080759f1aed3769896e94c73099f0fDan Williams
8576f231dda68080759f1aed3769896e94c73099f0fDan Williams	/* If the LUN reset worked, all the I/O can now be terminated. */
8586f231dda68080759f1aed3769896e94c73099f0fDan Williams	if (ret == TMF_RESP_FUNC_COMPLETE)
8596f231dda68080759f1aed3769896e94c73099f0fDan Williams		/* Terminate all I/O now. */
8606f231dda68080759f1aed3769896e94c73099f0fDan Williams		isci_terminate_pending_requests(isci_host,
861980d3aeb3828b0fdf2a0b2e893d238130b014575Dan Williams						isci_device);
8626f231dda68080759f1aed3769896e94c73099f0fDan Williams
863209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams out:
864209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	isci_put_device(isci_device);
8656f231dda68080759f1aed3769896e94c73099f0fDan Williams	return ret;
8666f231dda68080759f1aed3769896e94c73099f0fDan Williams}
8676f231dda68080759f1aed3769896e94c73099f0fDan Williams
8686f231dda68080759f1aed3769896e94c73099f0fDan Williams
8696f231dda68080759f1aed3769896e94c73099f0fDan Williams/*	 int (*lldd_clear_nexus_port)(struct asd_sas_port *); */
8706f231dda68080759f1aed3769896e94c73099f0fDan Williamsint isci_task_clear_nexus_port(struct asd_sas_port *port)
8716f231dda68080759f1aed3769896e94c73099f0fDan Williams{
8726f231dda68080759f1aed3769896e94c73099f0fDan Williams	return TMF_RESP_FUNC_FAILED;
8736f231dda68080759f1aed3769896e94c73099f0fDan Williams}
8746f231dda68080759f1aed3769896e94c73099f0fDan Williams
8756f231dda68080759f1aed3769896e94c73099f0fDan Williams
8766f231dda68080759f1aed3769896e94c73099f0fDan Williams
8776f231dda68080759f1aed3769896e94c73099f0fDan Williamsint isci_task_clear_nexus_ha(struct sas_ha_struct *ha)
8786f231dda68080759f1aed3769896e94c73099f0fDan Williams{
8796f231dda68080759f1aed3769896e94c73099f0fDan Williams	return TMF_RESP_FUNC_FAILED;
8806f231dda68080759f1aed3769896e94c73099f0fDan Williams}
8816f231dda68080759f1aed3769896e94c73099f0fDan Williams
8826f231dda68080759f1aed3769896e94c73099f0fDan Williams/* Task Management Functions. Must be called from process context.	 */
8836f231dda68080759f1aed3769896e94c73099f0fDan Williams
8846f231dda68080759f1aed3769896e94c73099f0fDan Williams/**
8856f231dda68080759f1aed3769896e94c73099f0fDan Williams * isci_abort_task_process_cb() - This is a helper function for the abort task
8866f231dda68080759f1aed3769896e94c73099f0fDan Williams *    TMF command.  It manages the request state with respect to the successful
8876f231dda68080759f1aed3769896e94c73099f0fDan Williams *    transmission / completion of the abort task request.
8886f231dda68080759f1aed3769896e94c73099f0fDan Williams * @cb_state: This parameter specifies when this function was called - after
8896f231dda68080759f1aed3769896e94c73099f0fDan Williams *    the TMF request has been started and after it has timed-out.
8906f231dda68080759f1aed3769896e94c73099f0fDan Williams * @tmf: This parameter specifies the TMF in progress.
8916f231dda68080759f1aed3769896e94c73099f0fDan Williams *
8926f231dda68080759f1aed3769896e94c73099f0fDan Williams *
8936f231dda68080759f1aed3769896e94c73099f0fDan Williams */
8946f231dda68080759f1aed3769896e94c73099f0fDan Williamsstatic void isci_abort_task_process_cb(
8956f231dda68080759f1aed3769896e94c73099f0fDan Williams	enum isci_tmf_cb_state cb_state,
8966f231dda68080759f1aed3769896e94c73099f0fDan Williams	struct isci_tmf *tmf,
8976f231dda68080759f1aed3769896e94c73099f0fDan Williams	void *cb_data)
8986f231dda68080759f1aed3769896e94c73099f0fDan Williams{
8996f231dda68080759f1aed3769896e94c73099f0fDan Williams	struct isci_request *old_request;
9006f231dda68080759f1aed3769896e94c73099f0fDan Williams
9016f231dda68080759f1aed3769896e94c73099f0fDan Williams	old_request = (struct isci_request *)cb_data;
9026f231dda68080759f1aed3769896e94c73099f0fDan Williams
9036f231dda68080759f1aed3769896e94c73099f0fDan Williams	dev_dbg(&old_request->isci_host->pdev->dev,
9046f231dda68080759f1aed3769896e94c73099f0fDan Williams		"%s: tmf=%p, old_request=%p\n",
9056f231dda68080759f1aed3769896e94c73099f0fDan Williams		__func__, tmf, old_request);
9066f231dda68080759f1aed3769896e94c73099f0fDan Williams
9076f231dda68080759f1aed3769896e94c73099f0fDan Williams	switch (cb_state) {
9086f231dda68080759f1aed3769896e94c73099f0fDan Williams
9096f231dda68080759f1aed3769896e94c73099f0fDan Williams	case isci_tmf_started:
9106f231dda68080759f1aed3769896e94c73099f0fDan Williams		/* The TMF has been started.  Nothing to do here, since the
9116f231dda68080759f1aed3769896e94c73099f0fDan Williams		 * request state was already set to "aborted" by the abort
9126f231dda68080759f1aed3769896e94c73099f0fDan Williams		 * task function.
9136f231dda68080759f1aed3769896e94c73099f0fDan Williams		 */
9146cb4d6b382be6345c2d0c4b1b90dfdf9af32da7eBartosz Barcinski		if ((old_request->status != aborted)
9156cb4d6b382be6345c2d0c4b1b90dfdf9af32da7eBartosz Barcinski			&& (old_request->status != completed))
916a8a0a133b03c6863d0f77229d19befca4de905faDan Williams			dev_dbg(&old_request->isci_host->pdev->dev,
9176cb4d6b382be6345c2d0c4b1b90dfdf9af32da7eBartosz Barcinski				"%s: Bad request status (%d): tmf=%p, old_request=%p\n",
9186cb4d6b382be6345c2d0c4b1b90dfdf9af32da7eBartosz Barcinski				__func__, old_request->status, tmf, old_request);
9196f231dda68080759f1aed3769896e94c73099f0fDan Williams		break;
9206f231dda68080759f1aed3769896e94c73099f0fDan Williams
9216f231dda68080759f1aed3769896e94c73099f0fDan Williams	case isci_tmf_timed_out:
9226f231dda68080759f1aed3769896e94c73099f0fDan Williams
9236f231dda68080759f1aed3769896e94c73099f0fDan Williams		/* Set the task's state to "aborting", since the abort task
9246f231dda68080759f1aed3769896e94c73099f0fDan Williams		 * function thread set it to "aborted" (above) in anticipation
9256f231dda68080759f1aed3769896e94c73099f0fDan Williams		 * of the task management request working correctly.  Since the
9266f231dda68080759f1aed3769896e94c73099f0fDan Williams		 * timeout has now fired, the TMF request failed.  We set the
9276f231dda68080759f1aed3769896e94c73099f0fDan Williams		 * state such that the request completion will indicate the
9286f231dda68080759f1aed3769896e94c73099f0fDan Williams		 * device is no longer present.
9296f231dda68080759f1aed3769896e94c73099f0fDan Williams		 */
9306f231dda68080759f1aed3769896e94c73099f0fDan Williams		isci_request_change_state(old_request, aborting);
9316f231dda68080759f1aed3769896e94c73099f0fDan Williams		break;
9326f231dda68080759f1aed3769896e94c73099f0fDan Williams
9336f231dda68080759f1aed3769896e94c73099f0fDan Williams	default:
934a8a0a133b03c6863d0f77229d19befca4de905faDan Williams		dev_dbg(&old_request->isci_host->pdev->dev,
9356f231dda68080759f1aed3769896e94c73099f0fDan Williams			"%s: Bad cb_state (%d): tmf=%p, old_request=%p\n",
9366f231dda68080759f1aed3769896e94c73099f0fDan Williams			__func__, cb_state, tmf, old_request);
9376f231dda68080759f1aed3769896e94c73099f0fDan Williams		break;
9386f231dda68080759f1aed3769896e94c73099f0fDan Williams	}
9396f231dda68080759f1aed3769896e94c73099f0fDan Williams}
9406f231dda68080759f1aed3769896e94c73099f0fDan Williams
9416f231dda68080759f1aed3769896e94c73099f0fDan Williams/**
9426f231dda68080759f1aed3769896e94c73099f0fDan Williams * isci_task_abort_task() - This function is one of the SAS Domain Template
9436f231dda68080759f1aed3769896e94c73099f0fDan Williams *    functions. This function is called by libsas to abort a specified task.
9446f231dda68080759f1aed3769896e94c73099f0fDan Williams * @task: This parameter specifies the SAS task to abort.
9456f231dda68080759f1aed3769896e94c73099f0fDan Williams *
9466f231dda68080759f1aed3769896e94c73099f0fDan Williams * status, zero indicates success.
9476f231dda68080759f1aed3769896e94c73099f0fDan Williams */
9486f231dda68080759f1aed3769896e94c73099f0fDan Williamsint isci_task_abort_task(struct sas_task *task)
9496f231dda68080759f1aed3769896e94c73099f0fDan Williams{
9504393aa4e6b9517a666f0ef6b774fd421a9dc4c68Dan Williams	struct isci_host *isci_host = dev_to_ihost(task->dev);
9516f231dda68080759f1aed3769896e94c73099f0fDan Williams	DECLARE_COMPLETION_ONSTACK(aborted_io_completion);
952a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin	struct isci_request       *old_request = NULL;
953a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin	enum isci_request_status  old_state;
9546f231dda68080759f1aed3769896e94c73099f0fDan Williams	struct isci_remote_device *isci_device = NULL;
955a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin	struct isci_tmf           tmf;
956a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin	int                       ret = TMF_RESP_FUNC_FAILED;
957a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin	unsigned long             flags;
95898145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin	int                       perform_termination = 0;
9596f231dda68080759f1aed3769896e94c73099f0fDan Williams
9606f231dda68080759f1aed3769896e94c73099f0fDan Williams	/* Get the isci_request reference from the task.  Note that
9616f231dda68080759f1aed3769896e94c73099f0fDan Williams	 * this check does not depend on the pending request list
9626f231dda68080759f1aed3769896e94c73099f0fDan Williams	 * in the device, because tasks driving resets may land here
9636f231dda68080759f1aed3769896e94c73099f0fDan Williams	 * after completion in the core.
9646f231dda68080759f1aed3769896e94c73099f0fDan Williams	 */
965209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	spin_lock_irqsave(&isci_host->scic_lock, flags);
966209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	spin_lock(&task->task_state_lock);
967209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams
968209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	old_request = task->lldd_task;
969209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams
970209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	/* If task is already done, the request isn't valid */
971209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	if (!(task->task_state_flags & SAS_TASK_STATE_DONE) &&
972209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	    (task->task_state_flags & SAS_TASK_AT_INITIATOR) &&
973209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	    old_request)
974209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams		isci_device = isci_lookup_device(task->dev);
975209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams
976209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	spin_unlock(&task->task_state_lock);
977209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	spin_unlock_irqrestore(&isci_host->scic_lock, flags);
9786f231dda68080759f1aed3769896e94c73099f0fDan Williams
9796f231dda68080759f1aed3769896e94c73099f0fDan Williams	dev_dbg(&isci_host->pdev->dev,
98098145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		"%s: dev = %p, task = %p, old_request == %p\n",
98198145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		__func__, isci_device, task, old_request);
9826f231dda68080759f1aed3769896e94c73099f0fDan Williams
98398145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin	/* Device reset conditions signalled in task_state_flags are the
98498145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin	 * responsbility of libsas to observe at the start of the error
98598145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin	 * handler thread.
9866f231dda68080759f1aed3769896e94c73099f0fDan Williams	 */
98798145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin	if (!isci_device || !old_request) {
98898145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		/* The request has already completed and there
98998145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		* is nothing to do here other than to set the task
99098145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		* done bit, and indicate that the task abort function
99198145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		* was sucessful.
99298145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		*/
99398145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		spin_lock_irqsave(&task->task_state_lock, flags);
99498145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		task->task_state_flags |= SAS_TASK_STATE_DONE;
99598145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
99698145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin					    SAS_TASK_STATE_PENDING);
99798145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		spin_unlock_irqrestore(&task->task_state_lock, flags);
9986f231dda68080759f1aed3769896e94c73099f0fDan Williams
99998145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		ret = TMF_RESP_FUNC_COMPLETE;
10006f231dda68080759f1aed3769896e94c73099f0fDan Williams
100198145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		dev_dbg(&isci_host->pdev->dev,
100298145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin			"%s: abort task not needed for %p\n",
100398145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin			__func__, task);
1004209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams		goto out;
1005a5ec7f86dc5432c44d8407a144e7617ec65da770James Bottomley	}
10066f231dda68080759f1aed3769896e94c73099f0fDan Williams
10076f231dda68080759f1aed3769896e94c73099f0fDan Williams	spin_lock_irqsave(&isci_host->scic_lock, flags);
10086f231dda68080759f1aed3769896e94c73099f0fDan Williams
1009f219f010a355487638bf2fff4724a420e7158fd2Jeff Skirvin	/* Check the request status and change to "aborted" if currently
1010a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin	 * "starting"; if true then set the I/O kernel completion
10116f231dda68080759f1aed3769896e94c73099f0fDan Williams	 * struct that will be triggered when the request completes.
10126f231dda68080759f1aed3769896e94c73099f0fDan Williams	 */
1013a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin	old_state = isci_task_validate_request_to_abort(
1014a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin				old_request, isci_host, isci_device,
1015a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin				&aborted_io_completion);
1016f219f010a355487638bf2fff4724a420e7158fd2Jeff Skirvin	if ((old_state != started) &&
1017f219f010a355487638bf2fff4724a420e7158fd2Jeff Skirvin	    (old_state != completed) &&
1018f219f010a355487638bf2fff4724a420e7158fd2Jeff Skirvin	    (old_state != aborting)) {
10196f231dda68080759f1aed3769896e94c73099f0fDan Williams
10206f231dda68080759f1aed3769896e94c73099f0fDan Williams		spin_unlock_irqrestore(&isci_host->scic_lock, flags);
10216f231dda68080759f1aed3769896e94c73099f0fDan Williams
1022a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin		/* The request was already being handled by someone else (because
1023a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin		* they got to set the state away from started).
1024a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin		*/
1025a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin		dev_dbg(&isci_host->pdev->dev,
1026a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin			"%s:  device = %p; old_request %p already being aborted\n",
1027a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin			__func__,
1028a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin			isci_device, old_request);
1029209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams		ret = TMF_RESP_FUNC_COMPLETE;
1030209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams		goto out;
10316f231dda68080759f1aed3769896e94c73099f0fDan Williams	}
103238d8879baeb61b6946052739e7c03fa79b3a57f0Dan Williams	if (task->task_proto == SAS_PROTOCOL_SMP ||
103398145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin	    sas_protocol_ata(task->task_proto) ||
103438d8879baeb61b6946052739e7c03fa79b3a57f0Dan Williams	    test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) {
10356f231dda68080759f1aed3769896e94c73099f0fDan Williams
10366f231dda68080759f1aed3769896e94c73099f0fDan Williams		spin_unlock_irqrestore(&isci_host->scic_lock, flags);
10376f231dda68080759f1aed3769896e94c73099f0fDan Williams
1038a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin		dev_dbg(&isci_host->pdev->dev,
103998145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin			"%s: %s request"
1040a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin			" or complete_in_target (%d), thus no TMF\n",
104198145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin			__func__,
104298145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin			((task->task_proto == SAS_PROTOCOL_SMP)
104398145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin				? "SMP"
104498145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin				: (sas_protocol_ata(task->task_proto)
104598145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin					? "SATA/STP"
104698145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin					: "<other>")
104798145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin			 ),
104838d8879baeb61b6946052739e7c03fa79b3a57f0Dan Williams			test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags));
1049a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin
105098145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		if (test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) {
105198145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin			spin_lock_irqsave(&task->task_state_lock, flags);
105298145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin			task->task_state_flags |= SAS_TASK_STATE_DONE;
105398145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin			task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
105498145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin						    SAS_TASK_STATE_PENDING);
105598145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin			spin_unlock_irqrestore(&task->task_state_lock, flags);
105698145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin			ret = TMF_RESP_FUNC_COMPLETE;
105798145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		} else {
105898145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin			spin_lock_irqsave(&task->task_state_lock, flags);
105998145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin			task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
106098145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin						    SAS_TASK_STATE_PENDING);
106198145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin			spin_unlock_irqrestore(&task->task_state_lock, flags);
106298145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		}
10636f231dda68080759f1aed3769896e94c73099f0fDan Williams
106498145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		/* STP and SMP devices are not sent a TMF, but the
106598145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		 * outstanding I/O request is terminated below.  This is
106698145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		 * because SATA/STP and SMP discovery path timeouts directly
106798145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		 * call the abort task interface for cleanup.
10686f231dda68080759f1aed3769896e94c73099f0fDan Williams		 */
106998145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		perform_termination = 1;
107098145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin
10716f231dda68080759f1aed3769896e94c73099f0fDan Williams	} else {
10726f231dda68080759f1aed3769896e94c73099f0fDan Williams		/* Fill in the tmf stucture */
1073209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams		isci_task_build_abort_task_tmf(&tmf, isci_tmf_ssp_task_abort,
1074c3f42feb0c3d20dc7007336e7de949408b93afefJeff Skirvin					       isci_abort_task_process_cb,
1075c3f42feb0c3d20dc7007336e7de949408b93afefJeff Skirvin					       old_request);
10766f231dda68080759f1aed3769896e94c73099f0fDan Williams
10776f231dda68080759f1aed3769896e94c73099f0fDan Williams		spin_unlock_irqrestore(&isci_host->scic_lock, flags);
10786f231dda68080759f1aed3769896e94c73099f0fDan Williams
107998145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		#define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* 1/2 second timeout */
1080209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams		ret = isci_task_execute_tmf(isci_host, isci_device, &tmf,
10816f231dda68080759f1aed3769896e94c73099f0fDan Williams					    ISCI_ABORT_TASK_TIMEOUT_MS);
10826f231dda68080759f1aed3769896e94c73099f0fDan Williams
108398145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		if (ret == TMF_RESP_FUNC_COMPLETE)
108498145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin			perform_termination = 1;
108598145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		else
1086a8a0a133b03c6863d0f77229d19befca4de905faDan Williams			dev_dbg(&isci_host->pdev->dev,
108798145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin				"%s: isci_task_send_tmf failed\n", __func__);
10886f231dda68080759f1aed3769896e94c73099f0fDan Williams	}
108998145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin	if (perform_termination) {
109038d8879baeb61b6946052739e7c03fa79b3a57f0Dan Williams		set_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags);
1091a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin
109277c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin		/* Clean up the request on our side, and wait for the aborted
109377c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin		 * I/O to complete.
109477c852f312243192b1f2ce7fc56d678784786692Jeff Skirvin		 */
109598145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin		isci_terminate_request_core(isci_host, isci_device,
109698145cb722b51ccc3ba27166c9803545accba950Jeff Skirvin					    old_request);
1097a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin	}
10986f231dda68080759f1aed3769896e94c73099f0fDan Williams
1099a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin	/* Make sure we do not leave a reference to aborted_io_completion */
1100a5fde225364df30507ba1a5aafeec85e595000d3Jeff Skirvin	old_request->io_request_completion = NULL;
1101209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams out:
1102209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	isci_put_device(isci_device);
11036f231dda68080759f1aed3769896e94c73099f0fDan Williams	return ret;
11046f231dda68080759f1aed3769896e94c73099f0fDan Williams}
11056f231dda68080759f1aed3769896e94c73099f0fDan Williams
11066f231dda68080759f1aed3769896e94c73099f0fDan Williams/**
11076f231dda68080759f1aed3769896e94c73099f0fDan Williams * isci_task_abort_task_set() - This function is one of the SAS Domain Template
11086f231dda68080759f1aed3769896e94c73099f0fDan Williams *    functions. This is one of the Task Management functoins called by libsas,
11096f231dda68080759f1aed3769896e94c73099f0fDan Williams *    to abort all task for the given lun.
11106f231dda68080759f1aed3769896e94c73099f0fDan Williams * @d_device: This parameter specifies the domain device associated with this
11116f231dda68080759f1aed3769896e94c73099f0fDan Williams *    request.
11126f231dda68080759f1aed3769896e94c73099f0fDan Williams * @lun: This parameter specifies the lun associated with this request.
11136f231dda68080759f1aed3769896e94c73099f0fDan Williams *
11146f231dda68080759f1aed3769896e94c73099f0fDan Williams * status, zero indicates success.
11156f231dda68080759f1aed3769896e94c73099f0fDan Williams */
11166f231dda68080759f1aed3769896e94c73099f0fDan Williamsint isci_task_abort_task_set(
11176f231dda68080759f1aed3769896e94c73099f0fDan Williams	struct domain_device *d_device,
11186f231dda68080759f1aed3769896e94c73099f0fDan Williams	u8 *lun)
11196f231dda68080759f1aed3769896e94c73099f0fDan Williams{
11206f231dda68080759f1aed3769896e94c73099f0fDan Williams	return TMF_RESP_FUNC_FAILED;
11216f231dda68080759f1aed3769896e94c73099f0fDan Williams}
11226f231dda68080759f1aed3769896e94c73099f0fDan Williams
11236f231dda68080759f1aed3769896e94c73099f0fDan Williams
11246f231dda68080759f1aed3769896e94c73099f0fDan Williams/**
11256f231dda68080759f1aed3769896e94c73099f0fDan Williams * isci_task_clear_aca() - This function is one of the SAS Domain Template
11266f231dda68080759f1aed3769896e94c73099f0fDan Williams *    functions. This is one of the Task Management functoins called by libsas.
11276f231dda68080759f1aed3769896e94c73099f0fDan Williams * @d_device: This parameter specifies the domain device associated with this
11286f231dda68080759f1aed3769896e94c73099f0fDan Williams *    request.
11296f231dda68080759f1aed3769896e94c73099f0fDan Williams * @lun: This parameter specifies the lun	 associated with this request.
11306f231dda68080759f1aed3769896e94c73099f0fDan Williams *
11316f231dda68080759f1aed3769896e94c73099f0fDan Williams * status, zero indicates success.
11326f231dda68080759f1aed3769896e94c73099f0fDan Williams */
11336f231dda68080759f1aed3769896e94c73099f0fDan Williamsint isci_task_clear_aca(
11346f231dda68080759f1aed3769896e94c73099f0fDan Williams	struct domain_device *d_device,
11356f231dda68080759f1aed3769896e94c73099f0fDan Williams	u8 *lun)
11366f231dda68080759f1aed3769896e94c73099f0fDan Williams{
11376f231dda68080759f1aed3769896e94c73099f0fDan Williams	return TMF_RESP_FUNC_FAILED;
11386f231dda68080759f1aed3769896e94c73099f0fDan Williams}
11396f231dda68080759f1aed3769896e94c73099f0fDan Williams
11406f231dda68080759f1aed3769896e94c73099f0fDan Williams
11416f231dda68080759f1aed3769896e94c73099f0fDan Williams
11426f231dda68080759f1aed3769896e94c73099f0fDan Williams/**
11436f231dda68080759f1aed3769896e94c73099f0fDan Williams * isci_task_clear_task_set() - This function is one of the SAS Domain Template
11446f231dda68080759f1aed3769896e94c73099f0fDan Williams *    functions. This is one of the Task Management functoins called by libsas.
11456f231dda68080759f1aed3769896e94c73099f0fDan Williams * @d_device: This parameter specifies the domain device associated with this
11466f231dda68080759f1aed3769896e94c73099f0fDan Williams *    request.
11476f231dda68080759f1aed3769896e94c73099f0fDan Williams * @lun: This parameter specifies the lun	 associated with this request.
11486f231dda68080759f1aed3769896e94c73099f0fDan Williams *
11496f231dda68080759f1aed3769896e94c73099f0fDan Williams * status, zero indicates success.
11506f231dda68080759f1aed3769896e94c73099f0fDan Williams */
11516f231dda68080759f1aed3769896e94c73099f0fDan Williamsint isci_task_clear_task_set(
11526f231dda68080759f1aed3769896e94c73099f0fDan Williams	struct domain_device *d_device,
11536f231dda68080759f1aed3769896e94c73099f0fDan Williams	u8 *lun)
11546f231dda68080759f1aed3769896e94c73099f0fDan Williams{
11556f231dda68080759f1aed3769896e94c73099f0fDan Williams	return TMF_RESP_FUNC_FAILED;
11566f231dda68080759f1aed3769896e94c73099f0fDan Williams}
11576f231dda68080759f1aed3769896e94c73099f0fDan Williams
11586f231dda68080759f1aed3769896e94c73099f0fDan Williams
11596f231dda68080759f1aed3769896e94c73099f0fDan Williams/**
11606f231dda68080759f1aed3769896e94c73099f0fDan Williams * isci_task_query_task() - This function is implemented to cause libsas to
11616f231dda68080759f1aed3769896e94c73099f0fDan Williams *    correctly escalate the failed abort to a LUN or target reset (this is
11626f231dda68080759f1aed3769896e94c73099f0fDan Williams *    because sas_scsi_find_task libsas function does not correctly interpret
11636f231dda68080759f1aed3769896e94c73099f0fDan Williams *    all return codes from the abort task call).  When TMF_RESP_FUNC_SUCC is
11646f231dda68080759f1aed3769896e94c73099f0fDan Williams *    returned, libsas turns this into a LUN reset; when FUNC_FAILED is
11656f231dda68080759f1aed3769896e94c73099f0fDan Williams *    returned, libsas will turn this into a target reset
11666f231dda68080759f1aed3769896e94c73099f0fDan Williams * @task: This parameter specifies the sas task being queried.
11676f231dda68080759f1aed3769896e94c73099f0fDan Williams * @lun: This parameter specifies the lun associated with this request.
11686f231dda68080759f1aed3769896e94c73099f0fDan Williams *
11696f231dda68080759f1aed3769896e94c73099f0fDan Williams * status, zero indicates success.
11706f231dda68080759f1aed3769896e94c73099f0fDan Williams */
11716f231dda68080759f1aed3769896e94c73099f0fDan Williamsint isci_task_query_task(
11726f231dda68080759f1aed3769896e94c73099f0fDan Williams	struct sas_task *task)
11736f231dda68080759f1aed3769896e94c73099f0fDan Williams{
11746f231dda68080759f1aed3769896e94c73099f0fDan Williams	/* See if there is a pending device reset for this device. */
11756f231dda68080759f1aed3769896e94c73099f0fDan Williams	if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET)
11766f231dda68080759f1aed3769896e94c73099f0fDan Williams		return TMF_RESP_FUNC_FAILED;
11776f231dda68080759f1aed3769896e94c73099f0fDan Williams	else
11786f231dda68080759f1aed3769896e94c73099f0fDan Williams		return TMF_RESP_FUNC_SUCC;
11796f231dda68080759f1aed3769896e94c73099f0fDan Williams}
11806f231dda68080759f1aed3769896e94c73099f0fDan Williams
1181af5ae89350840b9d724fc4fb81d928673bffdd4dDave Jiang/*
11826f231dda68080759f1aed3769896e94c73099f0fDan Williams * isci_task_request_complete() - This function is called by the sci core when
11836f231dda68080759f1aed3769896e94c73099f0fDan Williams *    an task request completes.
1184af5ae89350840b9d724fc4fb81d928673bffdd4dDave Jiang * @ihost: This parameter specifies the ISCI host object
1185af5ae89350840b9d724fc4fb81d928673bffdd4dDave Jiang * @ireq: This parameter is the completed isci_request object.
11866f231dda68080759f1aed3769896e94c73099f0fDan Williams * @completion_status: This parameter specifies the completion status from the
11876f231dda68080759f1aed3769896e94c73099f0fDan Williams *    sci core.
11886f231dda68080759f1aed3769896e94c73099f0fDan Williams *
11896f231dda68080759f1aed3769896e94c73099f0fDan Williams * none.
11906f231dda68080759f1aed3769896e94c73099f0fDan Williams */
1191af5ae89350840b9d724fc4fb81d928673bffdd4dDave Jiangvoid
1192af5ae89350840b9d724fc4fb81d928673bffdd4dDave Jiangisci_task_request_complete(struct isci_host *ihost,
1193af5ae89350840b9d724fc4fb81d928673bffdd4dDave Jiang			   struct isci_request *ireq,
1194af5ae89350840b9d724fc4fb81d928673bffdd4dDave Jiang			   enum sci_task_status completion_status)
11956f231dda68080759f1aed3769896e94c73099f0fDan Williams{
1196af5ae89350840b9d724fc4fb81d928673bffdd4dDave Jiang	struct isci_tmf *tmf = isci_request_access_tmf(ireq);
1197b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	struct completion *tmf_complete = NULL;
1198b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	struct completion *request_complete = ireq->io_request_completion;
11996f231dda68080759f1aed3769896e94c73099f0fDan Williams
1200af5ae89350840b9d724fc4fb81d928673bffdd4dDave Jiang	dev_dbg(&ihost->pdev->dev,
12016f231dda68080759f1aed3769896e94c73099f0fDan Williams		"%s: request = %p, status=%d\n",
1202af5ae89350840b9d724fc4fb81d928673bffdd4dDave Jiang		__func__, ireq, completion_status);
12036f231dda68080759f1aed3769896e94c73099f0fDan Williams
12048d2c65c09c9e0adc16070562e7944c1c3277f332Dave Jiang	isci_request_change_state(ireq, completed);
12056f231dda68080759f1aed3769896e94c73099f0fDan Williams
120638d8879baeb61b6946052739e7c03fa79b3a57f0Dan Williams	set_bit(IREQ_COMPLETE_IN_TARGET, &ireq->flags);
12076f231dda68080759f1aed3769896e94c73099f0fDan Williams
1208b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	if (tmf) {
1209b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		tmf->status = completion_status;
1210b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin
1211b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		if (tmf->proto == SAS_PROTOCOL_SSP) {
1212b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			memcpy(&tmf->resp.resp_iu,
1213b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			       &ireq->ssp.rsp,
1214b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			       SSP_RESP_IU_MAX_SIZE);
1215b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		} else if (tmf->proto == SAS_PROTOCOL_SATA) {
1216b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			memcpy(&tmf->resp.d2h_fis,
1217b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			       &ireq->stp.rsp,
1218b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin			       sizeof(struct dev_to_host_fis));
1219b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		}
1220b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		/* PRINT_TMF( ((struct isci_tmf *)request->task)); */
1221b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		tmf_complete = tmf->complete;
12226f231dda68080759f1aed3769896e94c73099f0fDan Williams	}
122389a7301f21fb00e753089671eb9e4132aab8ea08Dan Williams	sci_controller_complete_io(ihost, ireq->target_device, ireq);
122467ea838d17acdad3331aeae848683c768df96aaaDan Williams	/* set the 'terminated' flag handle to make sure it cannot be terminated
12256f231dda68080759f1aed3769896e94c73099f0fDan Williams	 *  or completed again.
12266f231dda68080759f1aed3769896e94c73099f0fDan Williams	 */
122738d8879baeb61b6946052739e7c03fa79b3a57f0Dan Williams	set_bit(IREQ_TERMINATED, &ireq->flags);
12286f231dda68080759f1aed3769896e94c73099f0fDan Williams
1229d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin	/* As soon as something is in the terminate path, deallocation is
1230d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin	 * managed there.  Note that the final non-managed state of a task
1231d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin	 * request is "completed".
1232d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin	 */
1233d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin	if ((ireq->status == completed) ||
1234d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin	    !isci_request_is_dealloc_managed(ireq->status)) {
1235d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin		isci_request_change_state(ireq, unallocated);
1236d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin		isci_free_tag(ihost, ireq->io_tag);
1237d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin		list_del_init(&ireq->dev_node);
1238d6891682220c18c01bf6838f30e37342c38fde44Jeff Skirvin	}
12396f231dda68080759f1aed3769896e94c73099f0fDan Williams
1240b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	/* "request_complete" is set if the task was being terminated. */
1241b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	if (request_complete)
1242b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		complete(request_complete);
1243b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin
12446f231dda68080759f1aed3769896e94c73099f0fDan Williams	/* The task management part completes last. */
1245b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin	if (tmf_complete)
1246b343dff1a269bcc0eac123ef541c5476b03d52c1Jeff Skirvin		complete(tmf_complete);
12476f231dda68080759f1aed3769896e94c73099f0fDan Williams}
12486f231dda68080759f1aed3769896e94c73099f0fDan Williams
1249209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williamsstatic int isci_reset_device(struct isci_host *ihost,
12509277699121b81891e303ada0a53fa1d04b7ffe72Dan Williams			     struct domain_device *dev,
1251bc6f387d3156702a0430585b93c04934254c0de1Jeff Skirvin			     struct isci_remote_device *idev)
12526f231dda68080759f1aed3769896e94c73099f0fDan Williams{
1253d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams	int rc;
12549277699121b81891e303ada0a53fa1d04b7ffe72Dan Williams	unsigned long flags;
12559277699121b81891e303ada0a53fa1d04b7ffe72Dan Williams	enum sci_status status;
12569277699121b81891e303ada0a53fa1d04b7ffe72Dan Williams	struct sas_phy *phy = sas_get_local_phy(dev);
12579277699121b81891e303ada0a53fa1d04b7ffe72Dan Williams	struct isci_port *iport = dev->port->lldd_port;
12586f231dda68080759f1aed3769896e94c73099f0fDan Williams
1259d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams	dev_dbg(&ihost->pdev->dev, "%s: idev %p\n", __func__, idev);
12606f231dda68080759f1aed3769896e94c73099f0fDan Williams
1261d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams	spin_lock_irqsave(&ihost->scic_lock, flags);
126289a7301f21fb00e753089671eb9e4132aab8ea08Dan Williams	status = sci_remote_device_reset(idev);
12639277699121b81891e303ada0a53fa1d04b7ffe72Dan Williams	spin_unlock_irqrestore(&ihost->scic_lock, flags);
12646f231dda68080759f1aed3769896e94c73099f0fDan Williams
12659277699121b81891e303ada0a53fa1d04b7ffe72Dan Williams	if (status != SCI_SUCCESS) {
1266a8a0a133b03c6863d0f77229d19befca4de905faDan Williams		dev_dbg(&ihost->pdev->dev,
126789a7301f21fb00e753089671eb9e4132aab8ea08Dan Williams			 "%s: sci_remote_device_reset(%p) returned %d!\n",
1268d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams			 __func__, idev, status);
1269f41a0c441c3fe43e79ebeb75584dbb5bfa83e5cdDan Williams		rc = TMF_RESP_FUNC_FAILED;
1270f41a0c441c3fe43e79ebeb75584dbb5bfa83e5cdDan Williams		goto out;
12716f231dda68080759f1aed3769896e94c73099f0fDan Williams	}
12726f231dda68080759f1aed3769896e94c73099f0fDan Williams
12739277699121b81891e303ada0a53fa1d04b7ffe72Dan Williams	if (scsi_is_sas_phy_local(phy)) {
12749277699121b81891e303ada0a53fa1d04b7ffe72Dan Williams		struct isci_phy *iphy = &ihost->phys[phy->number];
12759277699121b81891e303ada0a53fa1d04b7ffe72Dan Williams
12769277699121b81891e303ada0a53fa1d04b7ffe72Dan Williams		rc = isci_port_perform_hard_reset(ihost, iport, iphy);
12779277699121b81891e303ada0a53fa1d04b7ffe72Dan Williams	} else
12789277699121b81891e303ada0a53fa1d04b7ffe72Dan Williams		rc = sas_phy_reset(phy, !dev_is_sata(dev));
12796f231dda68080759f1aed3769896e94c73099f0fDan Williams
1280d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams	/* Terminate in-progress I/O now. */
1281d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams	isci_remote_device_nuke_requests(ihost, idev);
12826f231dda68080759f1aed3769896e94c73099f0fDan Williams
1283ff717ab05f0c33f93514eccea6dfe1a15983e1d1Jeff Skirvin	/* Since all pending TCs have been cleaned, resume the RNC. */
1284d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams	spin_lock_irqsave(&ihost->scic_lock, flags);
128589a7301f21fb00e753089671eb9e4132aab8ea08Dan Williams	status = sci_remote_device_reset_complete(idev);
1286d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams	spin_unlock_irqrestore(&ihost->scic_lock, flags);
12876f231dda68080759f1aed3769896e94c73099f0fDan Williams
1288d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams	if (status != SCI_SUCCESS) {
1289a8a0a133b03c6863d0f77229d19befca4de905faDan Williams		dev_dbg(&ihost->pdev->dev,
129089a7301f21fb00e753089671eb9e4132aab8ea08Dan Williams			 "%s: sci_remote_device_reset_complete(%p) "
1291d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams			 "returned %d!\n", __func__, idev, status);
12926f231dda68080759f1aed3769896e94c73099f0fDan Williams	}
12936f231dda68080759f1aed3769896e94c73099f0fDan Williams
1294d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams	dev_dbg(&ihost->pdev->dev, "%s: idev %p complete.\n", __func__, idev);
1295f41a0c441c3fe43e79ebeb75584dbb5bfa83e5cdDan Williams out:
1296f41a0c441c3fe43e79ebeb75584dbb5bfa83e5cdDan Williams	sas_put_local_phy(phy);
1297d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams	return rc;
1298d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams}
12996f231dda68080759f1aed3769896e94c73099f0fDan Williams
1300d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williamsint isci_task_I_T_nexus_reset(struct domain_device *dev)
1301d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams{
1302d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams	struct isci_host *ihost = dev_to_ihost(dev);
1303d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams	struct isci_remote_device *idev;
1304d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams	unsigned long flags;
1305bc6f387d3156702a0430585b93c04934254c0de1Jeff Skirvin	int ret;
1306d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams
1307d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams	spin_lock_irqsave(&ihost->scic_lock, flags);
1308209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	idev = isci_lookup_device(dev);
1309d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams	spin_unlock_irqrestore(&ihost->scic_lock, flags);
1310d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams
13115a998328296cb16cb8b0307a402a0f2feab533c5Dan Williams	if (!idev) {
13125a998328296cb16cb8b0307a402a0f2feab533c5Dan Williams		/* XXX: need to cleanup any ireqs targeting this
13135a998328296cb16cb8b0307a402a0f2feab533c5Dan Williams		 * domain_device
13145a998328296cb16cb8b0307a402a0f2feab533c5Dan Williams		 */
1315209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams		ret = TMF_RESP_FUNC_COMPLETE;
1316209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams		goto out;
1317209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	}
1318d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams
13199277699121b81891e303ada0a53fa1d04b7ffe72Dan Williams	ret = isci_reset_device(ihost, dev, idev);
1320209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams out:
1321209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	isci_put_device(idev);
1322209fae14fabfd48525e5630bebbbd4ca15090c60Dan Williams	return ret;
1323d06b487b78f28a02efdcdcc9ec295bf230b9d0e8Dan Williams}
1324