xref: /openbmc/linux/drivers/scsi/isci/request.c (revision 87832e937c808a7ebc41254b408362e3255c87c9)
16f231ddaSDan Williams /*
26f231ddaSDan Williams  * This file is provided under a dual BSD/GPLv2 license.  When using or
36f231ddaSDan Williams  * redistributing this file, you may do so under either license.
46f231ddaSDan Williams  *
56f231ddaSDan Williams  * GPL LICENSE SUMMARY
66f231ddaSDan Williams  *
76f231ddaSDan Williams  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
86f231ddaSDan Williams  *
96f231ddaSDan Williams  * This program is free software; you can redistribute it and/or modify
106f231ddaSDan Williams  * it under the terms of version 2 of the GNU General Public License as
116f231ddaSDan Williams  * published by the Free Software Foundation.
126f231ddaSDan Williams  *
136f231ddaSDan Williams  * This program is distributed in the hope that it will be useful, but
146f231ddaSDan Williams  * WITHOUT ANY WARRANTY; without even the implied warranty of
156f231ddaSDan Williams  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
166f231ddaSDan Williams  * General Public License for more details.
176f231ddaSDan Williams  *
186f231ddaSDan Williams  * You should have received a copy of the GNU General Public License
196f231ddaSDan Williams  * along with this program; if not, write to the Free Software
206f231ddaSDan Williams  * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
216f231ddaSDan Williams  * The full GNU General Public License is included in this distribution
226f231ddaSDan Williams  * in the file called LICENSE.GPL.
236f231ddaSDan Williams  *
246f231ddaSDan Williams  * BSD LICENSE
256f231ddaSDan Williams  *
266f231ddaSDan Williams  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
276f231ddaSDan Williams  * All rights reserved.
286f231ddaSDan Williams  *
296f231ddaSDan Williams  * Redistribution and use in source and binary forms, with or without
306f231ddaSDan Williams  * modification, are permitted provided that the following conditions
316f231ddaSDan Williams  * are met:
326f231ddaSDan Williams  *
336f231ddaSDan Williams  *   * Redistributions of source code must retain the above copyright
346f231ddaSDan Williams  *     notice, this list of conditions and the following disclaimer.
356f231ddaSDan Williams  *   * Redistributions in binary form must reproduce the above copyright
366f231ddaSDan Williams  *     notice, this list of conditions and the following disclaimer in
376f231ddaSDan Williams  *     the documentation and/or other materials provided with the
386f231ddaSDan Williams  *     distribution.
396f231ddaSDan Williams  *   * Neither the name of Intel Corporation nor the names of its
406f231ddaSDan Williams  *     contributors may be used to endorse or promote products derived
416f231ddaSDan Williams  *     from this software without specific prior written permission.
426f231ddaSDan Williams  *
436f231ddaSDan Williams  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
446f231ddaSDan Williams  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
456f231ddaSDan Williams  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
466f231ddaSDan Williams  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
476f231ddaSDan Williams  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
486f231ddaSDan Williams  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
496f231ddaSDan Williams  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
506f231ddaSDan Williams  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
516f231ddaSDan Williams  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
526f231ddaSDan Williams  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
536f231ddaSDan Williams  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
546f231ddaSDan Williams  */
556f231ddaSDan Williams 
563d2d7525SDave Jiang #include <scsi/scsi_cmnd.h>
576f231ddaSDan Williams #include "isci.h"
586f231ddaSDan Williams #include "task.h"
596f231ddaSDan Williams #include "request.h"
606f231ddaSDan Williams #include "scu_completion_codes.h"
615dec6f4eSDan Williams #include "scu_event_codes.h"
622ec53eb4SDave Jiang #include "sas.h"
636f231ddaSDan Williams 
64d7a0ccddSDan Williams #undef C
65d7a0ccddSDan Williams #define C(a) (#a)
req_state_name(enum sci_base_request_states state)66d7a0ccddSDan Williams const char *req_state_name(enum sci_base_request_states state)
67d7a0ccddSDan Williams {
68d7a0ccddSDan Williams 	static const char * const strings[] = REQUEST_STATES;
69d7a0ccddSDan Williams 
70d7a0ccddSDan Williams 	return strings[state];
71d7a0ccddSDan Williams }
72d7a0ccddSDan Williams #undef C
73d7a0ccddSDan Williams 
to_sgl_element_pair(struct isci_request * ireq,int idx)745076a1a9SDan Williams static struct scu_sgl_element_pair *to_sgl_element_pair(struct isci_request *ireq,
75312e0c24SDan Williams 							int idx)
76312e0c24SDan Williams {
77312e0c24SDan Williams 	if (idx == 0)
785076a1a9SDan Williams 		return &ireq->tc->sgl_pair_ab;
79312e0c24SDan Williams 	else if (idx == 1)
805076a1a9SDan Williams 		return &ireq->tc->sgl_pair_cd;
81312e0c24SDan Williams 	else if (idx < 0)
82312e0c24SDan Williams 		return NULL;
83312e0c24SDan Williams 	else
845076a1a9SDan Williams 		return &ireq->sg_table[idx - 2];
85f1f52e75SDan Williams }
866f231ddaSDan Williams 
to_sgl_element_pair_dma(struct isci_host * ihost,struct isci_request * ireq,u32 idx)87d9dcb4baSDan Williams static dma_addr_t to_sgl_element_pair_dma(struct isci_host *ihost,
885076a1a9SDan Williams 					  struct isci_request *ireq, u32 idx)
89312e0c24SDan Williams {
90312e0c24SDan Williams 	u32 offset;
91312e0c24SDan Williams 
92312e0c24SDan Williams 	if (idx == 0) {
935076a1a9SDan Williams 		offset = (void *) &ireq->tc->sgl_pair_ab -
94d9dcb4baSDan Williams 			 (void *) &ihost->task_context_table[0];
95abec912dSDan Williams 		return ihost->tc_dma + offset;
96312e0c24SDan Williams 	} else if (idx == 1) {
975076a1a9SDan Williams 		offset = (void *) &ireq->tc->sgl_pair_cd -
98d9dcb4baSDan Williams 			 (void *) &ihost->task_context_table[0];
99abec912dSDan Williams 		return ihost->tc_dma + offset;
1006f231ddaSDan Williams 	}
1016f231ddaSDan Williams 
10289a7301fSDan Williams 	return sci_io_request_get_dma_addr(ireq, &ireq->sg_table[idx - 2]);
103312e0c24SDan Williams }
104312e0c24SDan Williams 
init_sgl_element(struct scu_sgl_element * e,struct scatterlist * sg)105312e0c24SDan Williams static void init_sgl_element(struct scu_sgl_element *e, struct scatterlist *sg)
106312e0c24SDan Williams {
107312e0c24SDan Williams 	e->length = sg_dma_len(sg);
108312e0c24SDan Williams 	e->address_upper = upper_32_bits(sg_dma_address(sg));
109312e0c24SDan Williams 	e->address_lower = lower_32_bits(sg_dma_address(sg));
110312e0c24SDan Williams 	e->address_modifier = 0;
111312e0c24SDan Williams }
112312e0c24SDan Williams 
sci_request_build_sgl(struct isci_request * ireq)11389a7301fSDan Williams static void sci_request_build_sgl(struct isci_request *ireq)
114f1f52e75SDan Williams {
115d9dcb4baSDan Williams 	struct isci_host *ihost = ireq->isci_host;
1165076a1a9SDan Williams 	struct sas_task *task = isci_request_access_task(ireq);
117f1f52e75SDan Williams 	struct scatterlist *sg = NULL;
118f1f52e75SDan Williams 	dma_addr_t dma_addr;
119f1f52e75SDan Williams 	u32 sg_idx = 0;
120f1f52e75SDan Williams 	struct scu_sgl_element_pair *scu_sg   = NULL;
121f1f52e75SDan Williams 	struct scu_sgl_element_pair *prev_sg  = NULL;
122f1f52e75SDan Williams 
123f1f52e75SDan Williams 	if (task->num_scatter > 0) {
124f1f52e75SDan Williams 		sg = task->scatter;
125f1f52e75SDan Williams 
126f1f52e75SDan Williams 		while (sg) {
1275076a1a9SDan Williams 			scu_sg = to_sgl_element_pair(ireq, sg_idx);
128312e0c24SDan Williams 			init_sgl_element(&scu_sg->A, sg);
129f1f52e75SDan Williams 			sg = sg_next(sg);
130f1f52e75SDan Williams 			if (sg) {
131312e0c24SDan Williams 				init_sgl_element(&scu_sg->B, sg);
132f1f52e75SDan Williams 				sg = sg_next(sg);
133f1f52e75SDan Williams 			} else
134312e0c24SDan Williams 				memset(&scu_sg->B, 0, sizeof(scu_sg->B));
135f1f52e75SDan Williams 
136f1f52e75SDan Williams 			if (prev_sg) {
137d9dcb4baSDan Williams 				dma_addr = to_sgl_element_pair_dma(ihost,
1385076a1a9SDan Williams 								   ireq,
139312e0c24SDan Williams 								   sg_idx);
140f1f52e75SDan Williams 
141f1f52e75SDan Williams 				prev_sg->next_pair_upper =
142f1f52e75SDan Williams 					upper_32_bits(dma_addr);
143f1f52e75SDan Williams 				prev_sg->next_pair_lower =
144f1f52e75SDan Williams 					lower_32_bits(dma_addr);
145f1f52e75SDan Williams 			}
146f1f52e75SDan Williams 
147f1f52e75SDan Williams 			prev_sg = scu_sg;
148f1f52e75SDan Williams 			sg_idx++;
149f1f52e75SDan Williams 		}
150f1f52e75SDan Williams 	} else {	/* handle when no sg */
1515076a1a9SDan Williams 		scu_sg = to_sgl_element_pair(ireq, sg_idx);
152f1f52e75SDan Williams 
153d9dcb4baSDan Williams 		dma_addr = dma_map_single(&ihost->pdev->dev,
154f1f52e75SDan Williams 					  task->scatter,
155f1f52e75SDan Williams 					  task->total_xfer_len,
156f1f52e75SDan Williams 					  task->data_dir);
157f1f52e75SDan Williams 
1585076a1a9SDan Williams 		ireq->zero_scatter_daddr = dma_addr;
159f1f52e75SDan Williams 
160f1f52e75SDan Williams 		scu_sg->A.length = task->total_xfer_len;
161f1f52e75SDan Williams 		scu_sg->A.address_upper = upper_32_bits(dma_addr);
162f1f52e75SDan Williams 		scu_sg->A.address_lower = lower_32_bits(dma_addr);
163f1f52e75SDan Williams 	}
164f1f52e75SDan Williams 
165f1f52e75SDan Williams 	if (scu_sg) {
166f1f52e75SDan Williams 		scu_sg->next_pair_upper = 0;
167f1f52e75SDan Williams 		scu_sg->next_pair_lower = 0;
168f1f52e75SDan Williams 	}
169f1f52e75SDan Williams }
170f1f52e75SDan Williams 
sci_io_request_build_ssp_command_iu(struct isci_request * ireq)17189a7301fSDan Williams static void sci_io_request_build_ssp_command_iu(struct isci_request *ireq)
172f1f52e75SDan Williams {
173f1f52e75SDan Williams 	struct ssp_cmd_iu *cmd_iu;
174f1f52e75SDan Williams 	struct sas_task *task = isci_request_access_task(ireq);
175f1f52e75SDan Williams 
1765076a1a9SDan Williams 	cmd_iu = &ireq->ssp.cmd;
177f1f52e75SDan Williams 
178f1f52e75SDan Williams 	memcpy(cmd_iu->LUN, task->ssp_task.LUN, 8);
179f1f52e75SDan Williams 	cmd_iu->add_cdb_len = 0;
180f1f52e75SDan Williams 	cmd_iu->_r_a = 0;
181f1f52e75SDan Williams 	cmd_iu->_r_b = 0;
182f1f52e75SDan Williams 	cmd_iu->en_fburst = 0; /* unsupported */
1834dc051ebSJohn Garry 	cmd_iu->task_prio = 0;
184f1f52e75SDan Williams 	cmd_iu->task_attr = task->ssp_task.task_attr;
185f1f52e75SDan Williams 	cmd_iu->_r_c = 0;
186f1f52e75SDan Williams 
187e73823f7SJames Bottomley 	sci_swab32_cpy(&cmd_iu->cdb, task->ssp_task.cmd->cmnd,
188e1be0980SJames Bottomley 		       (task->ssp_task.cmd->cmd_len+3) / sizeof(u32));
189f1f52e75SDan Williams }
190f1f52e75SDan Williams 
sci_task_request_build_ssp_task_iu(struct isci_request * ireq)19189a7301fSDan Williams static void sci_task_request_build_ssp_task_iu(struct isci_request *ireq)
192f1f52e75SDan Williams {
193f1f52e75SDan Williams 	struct ssp_task_iu *task_iu;
194f1f52e75SDan Williams 	struct sas_task *task = isci_request_access_task(ireq);
195f1f52e75SDan Williams 	struct isci_tmf *isci_tmf = isci_request_access_tmf(ireq);
196f1f52e75SDan Williams 
1975076a1a9SDan Williams 	task_iu = &ireq->ssp.tmf;
198f1f52e75SDan Williams 
199f1f52e75SDan Williams 	memset(task_iu, 0, sizeof(struct ssp_task_iu));
200f1f52e75SDan Williams 
201f1f52e75SDan Williams 	memcpy(task_iu->LUN, task->ssp_task.LUN, 8);
202f1f52e75SDan Williams 
203f1f52e75SDan Williams 	task_iu->task_func = isci_tmf->tmf_code;
204f1f52e75SDan Williams 	task_iu->task_tag =
2053b34c169SJeff Skirvin 		(test_bit(IREQ_TMF, &ireq->flags)) ?
206f1f52e75SDan Williams 		isci_tmf->io_tag :
207f1f52e75SDan Williams 		SCI_CONTROLLER_INVALID_IO_TAG;
208f1f52e75SDan Williams }
209f1f52e75SDan Williams 
210db35a083SLee Jones /*
211f1f52e75SDan Williams  * This method is will fill in the SCU Task Context for any type of SSP request.
212f1f52e75SDan Williams  */
scu_ssp_request_construct_task_context(struct isci_request * ireq,struct scu_task_context * task_context)213f5f44c6fSColin Ian King static void scu_ssp_request_construct_task_context(
2145076a1a9SDan Williams 	struct isci_request *ireq,
215f1f52e75SDan Williams 	struct scu_task_context *task_context)
216f1f52e75SDan Williams {
217f1f52e75SDan Williams 	dma_addr_t dma_addr;
21878a6f06eSDan Williams 	struct isci_remote_device *idev;
219ffe191c9SDan Williams 	struct isci_port *iport;
220f1f52e75SDan Williams 
22134a99158SDan Williams 	idev = ireq->target_device;
22234a99158SDan Williams 	iport = idev->owning_port;
223f1f52e75SDan Williams 
224881a9a54SGeert Uytterhoeven 	/* Fill in the TC with its required data */
225f1f52e75SDan Williams 	task_context->abort = 0;
226f1f52e75SDan Williams 	task_context->priority = 0;
227f1f52e75SDan Williams 	task_context->initiator_request = 1;
22878a6f06eSDan Williams 	task_context->connection_rate = idev->connection_rate;
22934a99158SDan Williams 	task_context->protocol_engine_index = ISCI_PEG;
23034a99158SDan Williams 	task_context->logical_port_index = iport->physical_port_index;
231f1f52e75SDan Williams 	task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP;
232f1f52e75SDan Williams 	task_context->valid = SCU_TASK_CONTEXT_VALID;
233f1f52e75SDan Williams 	task_context->context_type = SCU_TASK_CONTEXT_TYPE;
234f1f52e75SDan Williams 
23534a99158SDan Williams 	task_context->remote_node_index = idev->rnc.remote_node_index;
236f1f52e75SDan Williams 	task_context->command_code = 0;
237f1f52e75SDan Williams 
238f1f52e75SDan Williams 	task_context->link_layer_control = 0;
239f1f52e75SDan Williams 	task_context->do_not_dma_ssp_good_response = 1;
240f1f52e75SDan Williams 	task_context->strict_ordering = 0;
241f1f52e75SDan Williams 	task_context->control_frame = 0;
242f1f52e75SDan Williams 	task_context->timeout_enable = 0;
243f1f52e75SDan Williams 	task_context->block_guard_enable = 0;
244f1f52e75SDan Williams 
245f1f52e75SDan Williams 	task_context->address_modifier = 0;
246f1f52e75SDan Williams 
2475076a1a9SDan Williams 	/* task_context->type.ssp.tag = ireq->io_tag; */
248f1f52e75SDan Williams 	task_context->task_phase = 0x01;
249f1f52e75SDan Williams 
2505076a1a9SDan Williams 	ireq->post_context = (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC |
25134a99158SDan Williams 			      (ISCI_PEG << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) |
25234a99158SDan Williams 			      (iport->physical_port_index <<
253f1f52e75SDan Williams 			       SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) |
2545076a1a9SDan Williams 			      ISCI_TAG_TCI(ireq->io_tag));
255f1f52e75SDan Williams 
256f1f52e75SDan Williams 	/*
257f1f52e75SDan Williams 	 * Copy the physical address for the command buffer to the
258f1f52e75SDan Williams 	 * SCU Task Context
259f1f52e75SDan Williams 	 */
26089a7301fSDan Williams 	dma_addr = sci_io_request_get_dma_addr(ireq, &ireq->ssp.cmd);
261f1f52e75SDan Williams 
262f1f52e75SDan Williams 	task_context->command_iu_upper = upper_32_bits(dma_addr);
263f1f52e75SDan Williams 	task_context->command_iu_lower = lower_32_bits(dma_addr);
264f1f52e75SDan Williams 
265f1f52e75SDan Williams 	/*
266f1f52e75SDan Williams 	 * Copy the physical address for the response buffer to the
267f1f52e75SDan Williams 	 * SCU Task Context
268f1f52e75SDan Williams 	 */
26989a7301fSDan Williams 	dma_addr = sci_io_request_get_dma_addr(ireq, &ireq->ssp.rsp);
270f1f52e75SDan Williams 
271f1f52e75SDan Williams 	task_context->response_iu_upper = upper_32_bits(dma_addr);
272f1f52e75SDan Williams 	task_context->response_iu_lower = lower_32_bits(dma_addr);
273f1f52e75SDan Williams }
274f1f52e75SDan Williams 
scu_bg_blk_size(struct scsi_device * sdp)2753d2d7525SDave Jiang static u8 scu_bg_blk_size(struct scsi_device *sdp)
2763d2d7525SDave Jiang {
2773d2d7525SDave Jiang 	switch (sdp->sector_size) {
2783d2d7525SDave Jiang 	case 512:
2793d2d7525SDave Jiang 		return 0;
2803d2d7525SDave Jiang 	case 1024:
2813d2d7525SDave Jiang 		return 1;
2823d2d7525SDave Jiang 	case 4096:
2833d2d7525SDave Jiang 		return 3;
2843d2d7525SDave Jiang 	default:
2853d2d7525SDave Jiang 		return 0xff;
2863d2d7525SDave Jiang 	}
2873d2d7525SDave Jiang }
2883d2d7525SDave Jiang 
scu_dif_bytes(u32 len,u32 sector_size)2893d2d7525SDave Jiang static u32 scu_dif_bytes(u32 len, u32 sector_size)
2903d2d7525SDave Jiang {
2913d2d7525SDave Jiang 	return (len >> ilog2(sector_size)) * 8;
2923d2d7525SDave Jiang }
2933d2d7525SDave Jiang 
scu_ssp_ireq_dif_insert(struct isci_request * ireq,u8 type,u8 op)2943d2d7525SDave Jiang static void scu_ssp_ireq_dif_insert(struct isci_request *ireq, u8 type, u8 op)
2953d2d7525SDave Jiang {
2963d2d7525SDave Jiang 	struct scu_task_context *tc = ireq->tc;
2973d2d7525SDave Jiang 	struct scsi_cmnd *scmd = ireq->ttype_ptr.io_task_ptr->uldd_task;
2983d2d7525SDave Jiang 	u8 blk_sz = scu_bg_blk_size(scmd->device);
2993d2d7525SDave Jiang 
3003d2d7525SDave Jiang 	tc->block_guard_enable = 1;
3013d2d7525SDave Jiang 	tc->blk_prot_en = 1;
3023d2d7525SDave Jiang 	tc->blk_sz = blk_sz;
3033d2d7525SDave Jiang 	/* DIF write insert */
3043d2d7525SDave Jiang 	tc->blk_prot_func = 0x2;
3053d2d7525SDave Jiang 
3063d2d7525SDave Jiang 	tc->transfer_length_bytes += scu_dif_bytes(tc->transfer_length_bytes,
3073d2d7525SDave Jiang 						   scmd->device->sector_size);
3083d2d7525SDave Jiang 
3093d2d7525SDave Jiang 	/* always init to 0, used by hw */
3103d2d7525SDave Jiang 	tc->interm_crc_val = 0;
3113d2d7525SDave Jiang 
3123d2d7525SDave Jiang 	tc->init_crc_seed = 0;
3133d2d7525SDave Jiang 	tc->app_tag_verify = 0;
3143d2d7525SDave Jiang 	tc->app_tag_gen = 0;
3153d2d7525SDave Jiang 	tc->ref_tag_seed_verify = 0;
3163d2d7525SDave Jiang 
3173d2d7525SDave Jiang 	/* always init to same as bg_blk_sz */
3183d2d7525SDave Jiang 	tc->UD_bytes_immed_val = scmd->device->sector_size;
3193d2d7525SDave Jiang 
3203d2d7525SDave Jiang 	tc->reserved_DC_0 = 0;
3213d2d7525SDave Jiang 
3223d2d7525SDave Jiang 	/* always init to 8 */
3233d2d7525SDave Jiang 	tc->DIF_bytes_immed_val = 8;
3243d2d7525SDave Jiang 
3253d2d7525SDave Jiang 	tc->reserved_DC_1 = 0;
3263d2d7525SDave Jiang 	tc->bgc_blk_sz = scmd->device->sector_size;
3273d2d7525SDave Jiang 	tc->reserved_E0_0 = 0;
3283d2d7525SDave Jiang 	tc->app_tag_gen_mask = 0;
3293d2d7525SDave Jiang 
3303d2d7525SDave Jiang 	/** setup block guard control **/
3313d2d7525SDave Jiang 	tc->bgctl = 0;
3323d2d7525SDave Jiang 
3333d2d7525SDave Jiang 	/* DIF write insert */
3343d2d7525SDave Jiang 	tc->bgctl_f.op = 0x2;
3353d2d7525SDave Jiang 
3363d2d7525SDave Jiang 	tc->app_tag_verify_mask = 0;
3373d2d7525SDave Jiang 
3383d2d7525SDave Jiang 	/* must init to 0 for hw */
3393d2d7525SDave Jiang 	tc->blk_guard_err = 0;
3403d2d7525SDave Jiang 
3413d2d7525SDave Jiang 	tc->reserved_E8_0 = 0;
3423d2d7525SDave Jiang 
3433d2d7525SDave Jiang 	if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2))
3444cc0096eSMartin K. Petersen 		tc->ref_tag_seed_gen = scsi_prot_ref_tag(scmd);
3453d2d7525SDave Jiang 	else if (type & SCSI_PROT_DIF_TYPE3)
3463d2d7525SDave Jiang 		tc->ref_tag_seed_gen = 0;
3473d2d7525SDave Jiang }
3483d2d7525SDave Jiang 
scu_ssp_ireq_dif_strip(struct isci_request * ireq,u8 type,u8 op)3493d2d7525SDave Jiang static void scu_ssp_ireq_dif_strip(struct isci_request *ireq, u8 type, u8 op)
3503d2d7525SDave Jiang {
3513d2d7525SDave Jiang 	struct scu_task_context *tc = ireq->tc;
3523d2d7525SDave Jiang 	struct scsi_cmnd *scmd = ireq->ttype_ptr.io_task_ptr->uldd_task;
3533d2d7525SDave Jiang 	u8 blk_sz = scu_bg_blk_size(scmd->device);
3543d2d7525SDave Jiang 
3553d2d7525SDave Jiang 	tc->block_guard_enable = 1;
3563d2d7525SDave Jiang 	tc->blk_prot_en = 1;
3573d2d7525SDave Jiang 	tc->blk_sz = blk_sz;
3583d2d7525SDave Jiang 	/* DIF read strip */
3593d2d7525SDave Jiang 	tc->blk_prot_func = 0x1;
3603d2d7525SDave Jiang 
3613d2d7525SDave Jiang 	tc->transfer_length_bytes += scu_dif_bytes(tc->transfer_length_bytes,
3623d2d7525SDave Jiang 						   scmd->device->sector_size);
3633d2d7525SDave Jiang 
3643d2d7525SDave Jiang 	/* always init to 0, used by hw */
3653d2d7525SDave Jiang 	tc->interm_crc_val = 0;
3663d2d7525SDave Jiang 
3673d2d7525SDave Jiang 	tc->init_crc_seed = 0;
3683d2d7525SDave Jiang 	tc->app_tag_verify = 0;
3693d2d7525SDave Jiang 	tc->app_tag_gen = 0;
3703d2d7525SDave Jiang 
3713d2d7525SDave Jiang 	if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2))
3724cc0096eSMartin K. Petersen 		tc->ref_tag_seed_verify = scsi_prot_ref_tag(scmd);
3733d2d7525SDave Jiang 	else if (type & SCSI_PROT_DIF_TYPE3)
3743d2d7525SDave Jiang 		tc->ref_tag_seed_verify = 0;
3753d2d7525SDave Jiang 
3763d2d7525SDave Jiang 	/* always init to same as bg_blk_sz */
3773d2d7525SDave Jiang 	tc->UD_bytes_immed_val = scmd->device->sector_size;
3783d2d7525SDave Jiang 
3793d2d7525SDave Jiang 	tc->reserved_DC_0 = 0;
3803d2d7525SDave Jiang 
3813d2d7525SDave Jiang 	/* always init to 8 */
3823d2d7525SDave Jiang 	tc->DIF_bytes_immed_val = 8;
3833d2d7525SDave Jiang 
3843d2d7525SDave Jiang 	tc->reserved_DC_1 = 0;
3853d2d7525SDave Jiang 	tc->bgc_blk_sz = scmd->device->sector_size;
3863d2d7525SDave Jiang 	tc->reserved_E0_0 = 0;
3873d2d7525SDave Jiang 	tc->app_tag_gen_mask = 0;
3883d2d7525SDave Jiang 
3893d2d7525SDave Jiang 	/** setup block guard control **/
3903d2d7525SDave Jiang 	tc->bgctl = 0;
3913d2d7525SDave Jiang 
3923d2d7525SDave Jiang 	/* DIF read strip */
3933d2d7525SDave Jiang 	tc->bgctl_f.crc_verify = 1;
3943d2d7525SDave Jiang 	tc->bgctl_f.op = 0x1;
3953d2d7525SDave Jiang 	if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2)) {
3963d2d7525SDave Jiang 		tc->bgctl_f.ref_tag_chk = 1;
3973d2d7525SDave Jiang 		tc->bgctl_f.app_f_detect = 1;
3983d2d7525SDave Jiang 	} else if (type & SCSI_PROT_DIF_TYPE3)
3993d2d7525SDave Jiang 		tc->bgctl_f.app_ref_f_detect = 1;
4003d2d7525SDave Jiang 
4013d2d7525SDave Jiang 	tc->app_tag_verify_mask = 0;
4023d2d7525SDave Jiang 
4033d2d7525SDave Jiang 	/* must init to 0 for hw */
4043d2d7525SDave Jiang 	tc->blk_guard_err = 0;
4053d2d7525SDave Jiang 
4063d2d7525SDave Jiang 	tc->reserved_E8_0 = 0;
4073d2d7525SDave Jiang 	tc->ref_tag_seed_gen = 0;
4083d2d7525SDave Jiang }
4093d2d7525SDave Jiang 
410db35a083SLee Jones /*
411f1f52e75SDan Williams  * This method is will fill in the SCU Task Context for a SSP IO request.
412f1f52e75SDan Williams  */
scu_ssp_io_request_construct_task_context(struct isci_request * ireq,enum dma_data_direction dir,u32 len)4135076a1a9SDan Williams static void scu_ssp_io_request_construct_task_context(struct isci_request *ireq,
414f1f52e75SDan Williams 						      enum dma_data_direction dir,
415f1f52e75SDan Williams 						      u32 len)
416f1f52e75SDan Williams {
4175076a1a9SDan Williams 	struct scu_task_context *task_context = ireq->tc;
4183d2d7525SDave Jiang 	struct sas_task *sas_task = ireq->ttype_ptr.io_task_ptr;
4193d2d7525SDave Jiang 	struct scsi_cmnd *scmd = sas_task->uldd_task;
4203d2d7525SDave Jiang 	u8 prot_type = scsi_get_prot_type(scmd);
4213d2d7525SDave Jiang 	u8 prot_op = scsi_get_prot_op(scmd);
422f1f52e75SDan Williams 
423f5f44c6fSColin Ian King 	scu_ssp_request_construct_task_context(ireq, task_context);
424f1f52e75SDan Williams 
425f1f52e75SDan Williams 	task_context->ssp_command_iu_length =
426f1f52e75SDan Williams 		sizeof(struct ssp_cmd_iu) / sizeof(u32);
427f1f52e75SDan Williams 	task_context->type.ssp.frame_type = SSP_COMMAND;
428f1f52e75SDan Williams 
429f1f52e75SDan Williams 	switch (dir) {
430f1f52e75SDan Williams 	case DMA_FROM_DEVICE:
431f1f52e75SDan Williams 	case DMA_NONE:
432f1f52e75SDan Williams 	default:
433f1f52e75SDan Williams 		task_context->task_type = SCU_TASK_TYPE_IOREAD;
434f1f52e75SDan Williams 		break;
435f1f52e75SDan Williams 	case DMA_TO_DEVICE:
436f1f52e75SDan Williams 		task_context->task_type = SCU_TASK_TYPE_IOWRITE;
437f1f52e75SDan Williams 		break;
438f1f52e75SDan Williams 	}
439f1f52e75SDan Williams 
440f1f52e75SDan Williams 	task_context->transfer_length_bytes = len;
441f1f52e75SDan Williams 
442f1f52e75SDan Williams 	if (task_context->transfer_length_bytes > 0)
44389a7301fSDan Williams 		sci_request_build_sgl(ireq);
4443d2d7525SDave Jiang 
4453d2d7525SDave Jiang 	if (prot_type != SCSI_PROT_DIF_TYPE0) {
4463d2d7525SDave Jiang 		if (prot_op == SCSI_PROT_READ_STRIP)
4473d2d7525SDave Jiang 			scu_ssp_ireq_dif_strip(ireq, prot_type, prot_op);
4483d2d7525SDave Jiang 		else if (prot_op == SCSI_PROT_WRITE_INSERT)
4493d2d7525SDave Jiang 			scu_ssp_ireq_dif_insert(ireq, prot_type, prot_op);
4503d2d7525SDave Jiang 	}
451f1f52e75SDan Williams }
452f1f52e75SDan Williams 
453f1f52e75SDan Williams /**
454db35a083SLee Jones  * scu_ssp_task_request_construct_task_context() - This method will fill in
455db35a083SLee Jones  *    the SCU Task Context for a SSP Task request.  The following important
456db35a083SLee Jones  *    settings are utilized: -# priority == SCU_TASK_PRIORITY_HIGH.  This
457db35a083SLee Jones  *    ensures that the task request is issued ahead of other task destined
458db35a083SLee Jones  *    for the same Remote Node. -# task_type == SCU_TASK_TYPE_IOREAD.  This
459db35a083SLee Jones  *    simply indicates that a normal request type (i.e. non-raw frame) is
460db35a083SLee Jones  *    being utilized to perform task management. -#control_frame == 1.  This
461db35a083SLee Jones  *    ensures that the proper endianness is set so that the bytes are
462db35a083SLee Jones  *    transmitted in the right order for a task frame.
463db35a083SLee Jones  * @ireq: This parameter specifies the task request object being constructed.
464f1f52e75SDan Williams  */
scu_ssp_task_request_construct_task_context(struct isci_request * ireq)4655076a1a9SDan Williams static void scu_ssp_task_request_construct_task_context(struct isci_request *ireq)
466f1f52e75SDan Williams {
4675076a1a9SDan Williams 	struct scu_task_context *task_context = ireq->tc;
468f1f52e75SDan Williams 
469f5f44c6fSColin Ian King 	scu_ssp_request_construct_task_context(ireq, task_context);
470f1f52e75SDan Williams 
471f1f52e75SDan Williams 	task_context->control_frame                = 1;
472f1f52e75SDan Williams 	task_context->priority                     = SCU_TASK_PRIORITY_HIGH;
473f1f52e75SDan Williams 	task_context->task_type                    = SCU_TASK_TYPE_RAW_FRAME;
474f1f52e75SDan Williams 	task_context->transfer_length_bytes        = 0;
475f1f52e75SDan Williams 	task_context->type.ssp.frame_type          = SSP_TASK;
476f1f52e75SDan Williams 	task_context->ssp_command_iu_length =
477f1f52e75SDan Williams 		sizeof(struct ssp_task_iu) / sizeof(u32);
478f1f52e75SDan Williams }
479f1f52e75SDan Williams 
480f1f52e75SDan Williams /**
481db35a083SLee Jones  * scu_sata_request_construct_task_context()
4825dec6f4eSDan Williams  * This method is will fill in the SCU Task Context for any type of SATA
4835dec6f4eSDan Williams  *    request.  This is called from the various SATA constructors.
484a8604e44SLee Jones  * @ireq: The general IO request object which is to be used in
4855dec6f4eSDan Williams  *    constructing the SCU task context.
4865dec6f4eSDan Williams  * @task_context: The buffer pointer for the SCU task context which is being
4875dec6f4eSDan Williams  *    constructed.
488f1f52e75SDan Williams  *
4895dec6f4eSDan Williams  * The general io request construction is complete. The buffer assignment for
4905dec6f4eSDan Williams  * the command buffer is complete. none Revisit task context construction to
4915dec6f4eSDan Williams  * determine what is common for SSP/SMP/STP task context structures.
492f1f52e75SDan Williams  */
scu_sata_request_construct_task_context(struct isci_request * ireq,struct scu_task_context * task_context)493f5f44c6fSColin Ian King static void scu_sata_request_construct_task_context(
4945076a1a9SDan Williams 	struct isci_request *ireq,
4955dec6f4eSDan Williams 	struct scu_task_context *task_context)
4965dec6f4eSDan Williams {
4975dec6f4eSDan Williams 	dma_addr_t dma_addr;
49878a6f06eSDan Williams 	struct isci_remote_device *idev;
499ffe191c9SDan Williams 	struct isci_port *iport;
5005dec6f4eSDan Williams 
50134a99158SDan Williams 	idev = ireq->target_device;
50234a99158SDan Williams 	iport = idev->owning_port;
5035dec6f4eSDan Williams 
504881a9a54SGeert Uytterhoeven 	/* Fill in the TC with its required data */
5055dec6f4eSDan Williams 	task_context->abort = 0;
5065dec6f4eSDan Williams 	task_context->priority = SCU_TASK_PRIORITY_NORMAL;
5075dec6f4eSDan Williams 	task_context->initiator_request = 1;
50878a6f06eSDan Williams 	task_context->connection_rate = idev->connection_rate;
50934a99158SDan Williams 	task_context->protocol_engine_index = ISCI_PEG;
51034a99158SDan Williams 	task_context->logical_port_index = iport->physical_port_index;
5115dec6f4eSDan Williams 	task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_STP;
5125dec6f4eSDan Williams 	task_context->valid = SCU_TASK_CONTEXT_VALID;
5135dec6f4eSDan Williams 	task_context->context_type = SCU_TASK_CONTEXT_TYPE;
5145dec6f4eSDan Williams 
51534a99158SDan Williams 	task_context->remote_node_index = idev->rnc.remote_node_index;
5165dec6f4eSDan Williams 	task_context->command_code = 0;
5175dec6f4eSDan Williams 
5185dec6f4eSDan Williams 	task_context->link_layer_control = 0;
5195dec6f4eSDan Williams 	task_context->do_not_dma_ssp_good_response = 1;
5205dec6f4eSDan Williams 	task_context->strict_ordering = 0;
5215dec6f4eSDan Williams 	task_context->control_frame = 0;
5225dec6f4eSDan Williams 	task_context->timeout_enable = 0;
5235dec6f4eSDan Williams 	task_context->block_guard_enable = 0;
5245dec6f4eSDan Williams 
5255dec6f4eSDan Williams 	task_context->address_modifier = 0;
5265dec6f4eSDan Williams 	task_context->task_phase = 0x01;
5275dec6f4eSDan Williams 
5285dec6f4eSDan Williams 	task_context->ssp_command_iu_length =
5295dec6f4eSDan Williams 		(sizeof(struct host_to_dev_fis) - sizeof(u32)) / sizeof(u32);
5305dec6f4eSDan Williams 
5315dec6f4eSDan Williams 	/* Set the first word of the H2D REG FIS */
5325076a1a9SDan Williams 	task_context->type.words[0] = *(u32 *)&ireq->stp.cmd;
5335dec6f4eSDan Williams 
5345076a1a9SDan Williams 	ireq->post_context = (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC |
53534a99158SDan Williams 			      (ISCI_PEG << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) |
53634a99158SDan Williams 			      (iport->physical_port_index <<
5375dec6f4eSDan Williams 			       SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) |
5385076a1a9SDan Williams 			      ISCI_TAG_TCI(ireq->io_tag));
5395dec6f4eSDan Williams 	/*
5405dec6f4eSDan Williams 	 * Copy the physical address for the command buffer to the SCU Task
5415dec6f4eSDan Williams 	 * Context. We must offset the command buffer by 4 bytes because the
5425dec6f4eSDan Williams 	 * first 4 bytes are transfered in the body of the TC.
5435dec6f4eSDan Williams 	 */
54489a7301fSDan Williams 	dma_addr = sci_io_request_get_dma_addr(ireq,
5455076a1a9SDan Williams 						((char *) &ireq->stp.cmd) +
5465dec6f4eSDan Williams 						sizeof(u32));
5475dec6f4eSDan Williams 
5485dec6f4eSDan Williams 	task_context->command_iu_upper = upper_32_bits(dma_addr);
5495dec6f4eSDan Williams 	task_context->command_iu_lower = lower_32_bits(dma_addr);
5505dec6f4eSDan Williams 
5515dec6f4eSDan Williams 	/* SATA Requests do not have a response buffer */
5525dec6f4eSDan Williams 	task_context->response_iu_upper = 0;
5535dec6f4eSDan Williams 	task_context->response_iu_lower = 0;
5545dec6f4eSDan Williams }
5555dec6f4eSDan Williams 
scu_stp_raw_request_construct_task_context(struct isci_request * ireq)5565076a1a9SDan Williams static void scu_stp_raw_request_construct_task_context(struct isci_request *ireq)
5575dec6f4eSDan Williams {
5585076a1a9SDan Williams 	struct scu_task_context *task_context = ireq->tc;
5595dec6f4eSDan Williams 
560f5f44c6fSColin Ian King 	scu_sata_request_construct_task_context(ireq, task_context);
5615dec6f4eSDan Williams 
5625dec6f4eSDan Williams 	task_context->control_frame         = 0;
5635dec6f4eSDan Williams 	task_context->priority              = SCU_TASK_PRIORITY_NORMAL;
5645dec6f4eSDan Williams 	task_context->task_type             = SCU_TASK_TYPE_SATA_RAW_FRAME;
5655dec6f4eSDan Williams 	task_context->type.stp.fis_type     = FIS_REGH2D;
5665dec6f4eSDan Williams 	task_context->transfer_length_bytes = sizeof(struct host_to_dev_fis) - sizeof(u32);
5675dec6f4eSDan Williams }
5685dec6f4eSDan Williams 
sci_stp_pio_request_construct(struct isci_request * ireq,bool copy_rx_frame)56989a7301fSDan Williams static enum sci_status sci_stp_pio_request_construct(struct isci_request *ireq,
5705dec6f4eSDan Williams 							  bool copy_rx_frame)
5715dec6f4eSDan Williams {
5725076a1a9SDan Williams 	struct isci_stp_request *stp_req = &ireq->stp.req;
5735dec6f4eSDan Williams 
5745076a1a9SDan Williams 	scu_stp_raw_request_construct_task_context(ireq);
5755dec6f4eSDan Williams 
576ba7cb223SDan Williams 	stp_req->status = 0;
577ba7cb223SDan Williams 	stp_req->sgl.offset = 0;
578ba7cb223SDan Williams 	stp_req->sgl.set = SCU_SGL_ELEMENT_PAIR_A;
5795dec6f4eSDan Williams 
5805dec6f4eSDan Williams 	if (copy_rx_frame) {
58189a7301fSDan Williams 		sci_request_build_sgl(ireq);
582ba7cb223SDan Williams 		stp_req->sgl.index = 0;
5835dec6f4eSDan Williams 	} else {
5845dec6f4eSDan Williams 		/* The user does not want the data copied to the SGL buffer location */
585ba7cb223SDan Williams 		stp_req->sgl.index = -1;
5865dec6f4eSDan Williams 	}
5875dec6f4eSDan Williams 
5885dec6f4eSDan Williams 	return SCI_SUCCESS;
5895dec6f4eSDan Williams }
5905dec6f4eSDan Williams 
591db35a083SLee Jones /*
592db35a083SLee Jones  * sci_stp_optimized_request_construct()
593db35a083SLee Jones  * @ireq: This parameter specifies the request to be constructed as an
5945dec6f4eSDan Williams  *    optimized request.
5955dec6f4eSDan Williams  * @optimized_task_type: This parameter specifies whether the request is to be
5965dec6f4eSDan Williams  *    an UDMA request or a NCQ request. - A value of 0 indicates UDMA. - A
5975dec6f4eSDan Williams  *    value of 1 indicates NCQ.
5985dec6f4eSDan Williams  *
5995dec6f4eSDan Williams  * This method will perform request construction common to all types of STP
6005dec6f4eSDan Williams  * requests that are optimized by the silicon (i.e. UDMA, NCQ). This method
6015dec6f4eSDan Williams  * returns an indication as to whether the construction was successful.
6025dec6f4eSDan Williams  */
sci_stp_optimized_request_construct(struct isci_request * ireq,u8 optimized_task_type,u32 len,enum dma_data_direction dir)60389a7301fSDan Williams static void sci_stp_optimized_request_construct(struct isci_request *ireq,
6045dec6f4eSDan Williams 						     u8 optimized_task_type,
6055dec6f4eSDan Williams 						     u32 len,
6065dec6f4eSDan Williams 						     enum dma_data_direction dir)
6075dec6f4eSDan Williams {
6085076a1a9SDan Williams 	struct scu_task_context *task_context = ireq->tc;
6095dec6f4eSDan Williams 
6105dec6f4eSDan Williams 	/* Build the STP task context structure */
611f5f44c6fSColin Ian King 	scu_sata_request_construct_task_context(ireq, task_context);
6125dec6f4eSDan Williams 
6135dec6f4eSDan Williams 	/* Copy over the SGL elements */
61489a7301fSDan Williams 	sci_request_build_sgl(ireq);
6155dec6f4eSDan Williams 
6165dec6f4eSDan Williams 	/* Copy over the number of bytes to be transfered */
6175dec6f4eSDan Williams 	task_context->transfer_length_bytes = len;
6185dec6f4eSDan Williams 
6195dec6f4eSDan Williams 	if (dir == DMA_TO_DEVICE) {
6205dec6f4eSDan Williams 		/*
6215dec6f4eSDan Williams 		 * The difference between the DMA IN and DMA OUT request task type
6225dec6f4eSDan Williams 		 * values are consistent with the difference between FPDMA READ
6235dec6f4eSDan Williams 		 * and FPDMA WRITE values.  Add the supplied task type parameter
6245dec6f4eSDan Williams 		 * to this difference to set the task type properly for this
6255dec6f4eSDan Williams 		 * DATA OUT (WRITE) case. */
6265dec6f4eSDan Williams 		task_context->task_type = optimized_task_type + (SCU_TASK_TYPE_DMA_OUT
6275dec6f4eSDan Williams 								 - SCU_TASK_TYPE_DMA_IN);
6285dec6f4eSDan Williams 	} else {
6295dec6f4eSDan Williams 		/*
6305dec6f4eSDan Williams 		 * For the DATA IN (READ) case, simply save the supplied
6315dec6f4eSDan Williams 		 * optimized task type. */
6325dec6f4eSDan Williams 		task_context->task_type = optimized_task_type;
6335dec6f4eSDan Williams 	}
6345dec6f4eSDan Williams }
6355dec6f4eSDan Williams 
sci_atapi_construct(struct isci_request * ireq)636b50102d3SDan Williams static void sci_atapi_construct(struct isci_request *ireq)
637b50102d3SDan Williams {
638b50102d3SDan Williams 	struct host_to_dev_fis *h2d_fis = &ireq->stp.cmd;
639b50102d3SDan Williams 	struct sas_task *task;
6405dec6f4eSDan Williams 
641b50102d3SDan Williams 	/* To simplify the implementation we take advantage of the
642b50102d3SDan Williams 	 * silicon's partial acceleration of atapi protocol (dma data
643b50102d3SDan Williams 	 * transfers), so we promote all commands to dma protocol.  This
644b50102d3SDan Williams 	 * breaks compatibility with ATA_HORKAGE_ATAPI_MOD16_DMA drives.
645b50102d3SDan Williams 	 */
646b50102d3SDan Williams 	h2d_fis->features |= ATAPI_PKT_DMA;
647b50102d3SDan Williams 
648b50102d3SDan Williams 	scu_stp_raw_request_construct_task_context(ireq);
649b50102d3SDan Williams 
650b50102d3SDan Williams 	task = isci_request_access_task(ireq);
651b50102d3SDan Williams 	if (task->data_dir == DMA_NONE)
652b50102d3SDan Williams 		task->total_xfer_len = 0;
653b50102d3SDan Williams 
654b50102d3SDan Williams 	/* clear the response so we can detect arrivial of an
655b50102d3SDan Williams 	 * unsolicited h2d fis
656b50102d3SDan Williams 	 */
657b50102d3SDan Williams 	ireq->stp.rsp.fis_type = 0;
658b50102d3SDan Williams }
6595dec6f4eSDan Williams 
660f1f52e75SDan Williams static enum sci_status
sci_io_request_construct_sata(struct isci_request * ireq,u32 len,enum dma_data_direction dir,bool copy)66189a7301fSDan Williams sci_io_request_construct_sata(struct isci_request *ireq,
662f1f52e75SDan Williams 			       u32 len,
663f1f52e75SDan Williams 			       enum dma_data_direction dir,
664f1f52e75SDan Williams 			       bool copy)
6656f231ddaSDan Williams {
6666f231ddaSDan Williams 	enum sci_status status = SCI_SUCCESS;
667f1f52e75SDan Williams 	struct sas_task *task = isci_request_access_task(ireq);
668b50102d3SDan Williams 	struct domain_device *dev = ireq->target_device->domain_dev;
6696f231ddaSDan Williams 
670f1f52e75SDan Williams 	/* check for management protocols */
6713b34c169SJeff Skirvin 	if (test_bit(IREQ_TMF, &ireq->flags)) {
672f1f52e75SDan Williams 		struct isci_tmf *tmf = isci_request_access_tmf(ireq);
673f1f52e75SDan Williams 
674d9dcb4baSDan Williams 		dev_err(&ireq->owning_controller->pdev->dev,
675f1f52e75SDan Williams 			"%s: Request 0x%p received un-handled SAT "
676f1f52e75SDan Williams 			"management protocol 0x%x.\n",
6775076a1a9SDan Williams 			__func__, ireq, tmf->tmf_code);
678f1f52e75SDan Williams 
679f1f52e75SDan Williams 		return SCI_FAILURE;
680f1f52e75SDan Williams 	}
681f1f52e75SDan Williams 
682f1f52e75SDan Williams 	if (!sas_protocol_ata(task->task_proto)) {
683d9dcb4baSDan Williams 		dev_err(&ireq->owning_controller->pdev->dev,
684f1f52e75SDan Williams 			"%s: Non-ATA protocol in SATA path: 0x%x\n",
6856f231ddaSDan Williams 			__func__,
686f1f52e75SDan Williams 			task->task_proto);
6876f231ddaSDan Williams 		return SCI_FAILURE;
688f1f52e75SDan Williams 
6896f231ddaSDan Williams 	}
6906f231ddaSDan Williams 
691b50102d3SDan Williams 	/* ATAPI */
6921cbd772dSHannes Reinecke 	if (dev->sata_dev.class == ATA_DEV_ATAPI &&
693b50102d3SDan Williams 	    task->ata_task.fis.command == ATA_CMD_PACKET) {
694b50102d3SDan Williams 		sci_atapi_construct(ireq);
695b50102d3SDan Williams 		return SCI_SUCCESS;
696b50102d3SDan Williams 	}
697b50102d3SDan Williams 
698f1f52e75SDan Williams 	/* non data */
6995dec6f4eSDan Williams 	if (task->data_dir == DMA_NONE) {
7005076a1a9SDan Williams 		scu_stp_raw_request_construct_task_context(ireq);
7015dec6f4eSDan Williams 		return SCI_SUCCESS;
7025dec6f4eSDan Williams 	}
703f1f52e75SDan Williams 
704f1f52e75SDan Williams 	/* NCQ */
7055dec6f4eSDan Williams 	if (task->ata_task.use_ncq) {
70689a7301fSDan Williams 		sci_stp_optimized_request_construct(ireq,
7075dec6f4eSDan Williams 							 SCU_TASK_TYPE_FPDMAQ_READ,
7085dec6f4eSDan Williams 							 len, dir);
7095dec6f4eSDan Williams 		return SCI_SUCCESS;
7105dec6f4eSDan Williams 	}
711f1f52e75SDan Williams 
712f1f52e75SDan Williams 	/* DMA */
7135dec6f4eSDan Williams 	if (task->ata_task.dma_xfer) {
71489a7301fSDan Williams 		sci_stp_optimized_request_construct(ireq,
7155dec6f4eSDan Williams 							 SCU_TASK_TYPE_DMA_IN,
7165dec6f4eSDan Williams 							 len, dir);
7175dec6f4eSDan Williams 		return SCI_SUCCESS;
7185dec6f4eSDan Williams 	} else /* PIO */
71989a7301fSDan Williams 		return sci_stp_pio_request_construct(ireq, copy);
720f1f52e75SDan Williams 
721f1f52e75SDan Williams 	return status;
7226f231ddaSDan Williams }
7236f231ddaSDan Williams 
sci_io_request_construct_basic_ssp(struct isci_request * ireq)72489a7301fSDan Williams static enum sci_status sci_io_request_construct_basic_ssp(struct isci_request *ireq)
725f1f52e75SDan Williams {
726f1f52e75SDan Williams 	struct sas_task *task = isci_request_access_task(ireq);
727f1f52e75SDan Williams 
728c79dd80dSDan Williams 	ireq->protocol = SAS_PROTOCOL_SSP;
729f1f52e75SDan Williams 
7305076a1a9SDan Williams 	scu_ssp_io_request_construct_task_context(ireq,
731f1f52e75SDan Williams 						  task->data_dir,
732f1f52e75SDan Williams 						  task->total_xfer_len);
733f1f52e75SDan Williams 
73489a7301fSDan Williams 	sci_io_request_build_ssp_command_iu(ireq);
735f1f52e75SDan Williams 
7365076a1a9SDan Williams 	sci_change_state(&ireq->sm, SCI_REQ_CONSTRUCTED);
737f1f52e75SDan Williams 
738f1f52e75SDan Williams 	return SCI_SUCCESS;
739f1f52e75SDan Williams }
740f1f52e75SDan Williams 
sci_task_request_construct_ssp(struct isci_request * ireq)74189a7301fSDan Williams enum sci_status sci_task_request_construct_ssp(
7425076a1a9SDan Williams 	struct isci_request *ireq)
743f1f52e75SDan Williams {
744f1f52e75SDan Williams 	/* Construct the SSP Task SCU Task Context */
7455076a1a9SDan Williams 	scu_ssp_task_request_construct_task_context(ireq);
746f1f52e75SDan Williams 
747f1f52e75SDan Williams 	/* Fill in the SSP Task IU */
74889a7301fSDan Williams 	sci_task_request_build_ssp_task_iu(ireq);
749f1f52e75SDan Williams 
7505076a1a9SDan Williams 	sci_change_state(&ireq->sm, SCI_REQ_CONSTRUCTED);
751f1f52e75SDan Williams 
7526f231ddaSDan Williams 	return SCI_SUCCESS;
7536f231ddaSDan Williams }
7546f231ddaSDan Williams 
sci_io_request_construct_basic_sata(struct isci_request * ireq)75589a7301fSDan Williams static enum sci_status sci_io_request_construct_basic_sata(struct isci_request *ireq)
7566f231ddaSDan Williams {
757f1f52e75SDan Williams 	enum sci_status status;
758f1f52e75SDan Williams 	bool copy = false;
7595076a1a9SDan Williams 	struct sas_task *task = isci_request_access_task(ireq);
7606f231ddaSDan Williams 
761c79dd80dSDan Williams 	ireq->protocol = SAS_PROTOCOL_STP;
7626f231ddaSDan Williams 
763f1f52e75SDan Williams 	copy = (task->data_dir == DMA_NONE) ? false : true;
764f1f52e75SDan Williams 
76589a7301fSDan Williams 	status = sci_io_request_construct_sata(ireq,
766f1f52e75SDan Williams 						task->total_xfer_len,
767f1f52e75SDan Williams 						task->data_dir,
768f1f52e75SDan Williams 						copy);
769f1f52e75SDan Williams 
770f1f52e75SDan Williams 	if (status == SCI_SUCCESS)
7715076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_CONSTRUCTED);
772f1f52e75SDan Williams 
773f1f52e75SDan Williams 	return status;
7746f231ddaSDan Williams }
7756f231ddaSDan Williams 
776db35a083SLee Jones #define SCU_TASK_CONTEXT_SRAM 0x200000
7776f231ddaSDan Williams /**
778f1f52e75SDan Williams  * sci_req_tx_bytes - bytes transferred when reply underruns request
779b50102d3SDan Williams  * @ireq: request that was terminated early
7806f231ddaSDan Williams  */
sci_req_tx_bytes(struct isci_request * ireq)7815076a1a9SDan Williams static u32 sci_req_tx_bytes(struct isci_request *ireq)
7826f231ddaSDan Williams {
783d9dcb4baSDan Williams 	struct isci_host *ihost = ireq->owning_controller;
784f1f52e75SDan Williams 	u32 ret_val = 0;
7856f231ddaSDan Williams 
786d9dcb4baSDan Williams 	if (readl(&ihost->smu_registers->address_modifier) == 0) {
787d9dcb4baSDan Williams 		void __iomem *scu_reg_base = ihost->scu_registers;
7886f231ddaSDan Williams 
789f1f52e75SDan Williams 		/* get the bytes of data from the Address == BAR1 + 20002Ch + (256*TCi) where
790f1f52e75SDan Williams 		 *   BAR1 is the scu_registers
791f1f52e75SDan Williams 		 *   0x20002C = 0x200000 + 0x2c
792f1f52e75SDan Williams 		 *            = start of task context SRAM + offset of (type.ssp.data_offset)
79389a7301fSDan Williams 		 *   TCi is the io_tag of struct sci_request
794f1f52e75SDan Williams 		 */
795f1f52e75SDan Williams 		ret_val = readl(scu_reg_base +
796f1f52e75SDan Williams 				(SCU_TASK_CONTEXT_SRAM + offsetof(struct scu_task_context, type.ssp.data_offset)) +
7975076a1a9SDan Williams 				((sizeof(struct scu_task_context)) * ISCI_TAG_TCI(ireq->io_tag)));
7986f231ddaSDan Williams 	}
799f1f52e75SDan Williams 
800f1f52e75SDan Williams 	return ret_val;
801f1f52e75SDan Williams }
802f1f52e75SDan Williams 
sci_request_start(struct isci_request * ireq)80389a7301fSDan Williams enum sci_status sci_request_start(struct isci_request *ireq)
804f1f52e75SDan Williams {
805f4636a7bSPiotr Sawicki 	enum sci_base_request_states state;
8065076a1a9SDan Williams 	struct scu_task_context *tc = ireq->tc;
807d9dcb4baSDan Williams 	struct isci_host *ihost = ireq->owning_controller;
808f4636a7bSPiotr Sawicki 
8095076a1a9SDan Williams 	state = ireq->sm.current_state_id;
810e301370aSEdmund Nadolski 	if (state != SCI_REQ_CONSTRUCTED) {
811d9dcb4baSDan Williams 		dev_warn(&ihost->pdev->dev,
812f1f52e75SDan Williams 			"%s: SCIC IO Request requested to start while in wrong "
813f4636a7bSPiotr Sawicki 			 "state %d\n", __func__, state);
814f1f52e75SDan Williams 		return SCI_FAILURE_INVALID_STATE;
815f1f52e75SDan Williams 	}
816f1f52e75SDan Williams 
8175076a1a9SDan Williams 	tc->task_index = ISCI_TAG_TCI(ireq->io_tag);
818f4636a7bSPiotr Sawicki 
819312e0c24SDan Williams 	switch (tc->protocol_type) {
820f4636a7bSPiotr Sawicki 	case SCU_TASK_CONTEXT_PROTOCOL_SMP:
821f4636a7bSPiotr Sawicki 	case SCU_TASK_CONTEXT_PROTOCOL_SSP:
822f4636a7bSPiotr Sawicki 		/* SSP/SMP Frame */
8235076a1a9SDan Williams 		tc->type.ssp.tag = ireq->io_tag;
824312e0c24SDan Williams 		tc->type.ssp.target_port_transfer_tag = 0xFFFF;
825f4636a7bSPiotr Sawicki 		break;
826f4636a7bSPiotr Sawicki 
827f4636a7bSPiotr Sawicki 	case SCU_TASK_CONTEXT_PROTOCOL_STP:
828f4636a7bSPiotr Sawicki 		/* STP/SATA Frame
8295076a1a9SDan Williams 		 * tc->type.stp.ncq_tag = ireq->ncq_tag;
830f4636a7bSPiotr Sawicki 		 */
831f4636a7bSPiotr Sawicki 		break;
832f4636a7bSPiotr Sawicki 
833f4636a7bSPiotr Sawicki 	case SCU_TASK_CONTEXT_PROTOCOL_NONE:
834f4636a7bSPiotr Sawicki 		/* / @todo When do we set no protocol type? */
835f4636a7bSPiotr Sawicki 		break;
836f4636a7bSPiotr Sawicki 
837f4636a7bSPiotr Sawicki 	default:
838f4636a7bSPiotr Sawicki 		/* This should never happen since we build the IO
839f4636a7bSPiotr Sawicki 		 * requests */
840f4636a7bSPiotr Sawicki 		break;
841f4636a7bSPiotr Sawicki 	}
842f4636a7bSPiotr Sawicki 
843f4636a7bSPiotr Sawicki 	/* Add to the post_context the io tag value */
8445076a1a9SDan Williams 	ireq->post_context |= ISCI_TAG_TCI(ireq->io_tag);
845f4636a7bSPiotr Sawicki 
846f4636a7bSPiotr Sawicki 	/* Everything is good go ahead and change state */
8475076a1a9SDan Williams 	sci_change_state(&ireq->sm, SCI_REQ_STARTED);
848f4636a7bSPiotr Sawicki 
849f4636a7bSPiotr Sawicki 	return SCI_SUCCESS;
850f4636a7bSPiotr Sawicki }
851f4636a7bSPiotr Sawicki 
852f1f52e75SDan Williams enum sci_status
sci_io_request_terminate(struct isci_request * ireq)85389a7301fSDan Williams sci_io_request_terminate(struct isci_request *ireq)
854f1f52e75SDan Williams {
855f00e6ba4SDan Williams 	enum sci_base_request_states state;
856f1f52e75SDan Williams 
8575076a1a9SDan Williams 	state = ireq->sm.current_state_id;
858f00e6ba4SDan Williams 
859f00e6ba4SDan Williams 	switch (state) {
860e301370aSEdmund Nadolski 	case SCI_REQ_CONSTRUCTED:
861726980d5SJeff Skirvin 		/* Set to make sure no HW terminate posting is done: */
862726980d5SJeff Skirvin 		set_bit(IREQ_TC_ABORT_POSTED, &ireq->flags);
86334a99158SDan Williams 		ireq->scu_status = SCU_TASK_DONE_TASK_ABORT;
86434a99158SDan Williams 		ireq->sci_status = SCI_FAILURE_IO_TERMINATED;
8655076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
866f00e6ba4SDan Williams 		return SCI_SUCCESS;
867e301370aSEdmund Nadolski 	case SCI_REQ_STARTED:
868e301370aSEdmund Nadolski 	case SCI_REQ_TASK_WAIT_TC_COMP:
869e301370aSEdmund Nadolski 	case SCI_REQ_SMP_WAIT_RESP:
870e301370aSEdmund Nadolski 	case SCI_REQ_SMP_WAIT_TC_COMP:
871e301370aSEdmund Nadolski 	case SCI_REQ_STP_UDMA_WAIT_TC_COMP:
872e301370aSEdmund Nadolski 	case SCI_REQ_STP_UDMA_WAIT_D2H:
873e301370aSEdmund Nadolski 	case SCI_REQ_STP_NON_DATA_WAIT_H2D:
874e301370aSEdmund Nadolski 	case SCI_REQ_STP_NON_DATA_WAIT_D2H:
875e301370aSEdmund Nadolski 	case SCI_REQ_STP_PIO_WAIT_H2D:
876e301370aSEdmund Nadolski 	case SCI_REQ_STP_PIO_WAIT_FRAME:
877e301370aSEdmund Nadolski 	case SCI_REQ_STP_PIO_DATA_IN:
878e301370aSEdmund Nadolski 	case SCI_REQ_STP_PIO_DATA_OUT:
879b50102d3SDan Williams 	case SCI_REQ_ATAPI_WAIT_H2D:
880b50102d3SDan Williams 	case SCI_REQ_ATAPI_WAIT_PIO_SETUP:
881b50102d3SDan Williams 	case SCI_REQ_ATAPI_WAIT_D2H:
882b50102d3SDan Williams 	case SCI_REQ_ATAPI_WAIT_TC_COMP:
883726980d5SJeff Skirvin 		/* Fall through and change state to ABORTING... */
884e301370aSEdmund Nadolski 	case SCI_REQ_TASK_WAIT_TC_RESP:
88539ea2c5bSJeff Skirvin 		/* The task frame was already confirmed to have been
88639ea2c5bSJeff Skirvin 		 * sent by the SCU HW.  Since the state machine is
88739ea2c5bSJeff Skirvin 		 * now only waiting for the task response itself,
88839ea2c5bSJeff Skirvin 		 * abort the request and complete it immediately
88939ea2c5bSJeff Skirvin 		 * and don't wait for the task response.
89039ea2c5bSJeff Skirvin 		 */
8915076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_ABORTING);
892df561f66SGustavo A. R. Silva 		fallthrough;	/* and handle like ABORTING */
893e301370aSEdmund Nadolski 	case SCI_REQ_ABORTING:
894726980d5SJeff Skirvin 		if (!isci_remote_device_is_safe_to_abort(ireq->target_device))
895726980d5SJeff Skirvin 			set_bit(IREQ_PENDING_ABORT, &ireq->flags);
896726980d5SJeff Skirvin 		else
897726980d5SJeff Skirvin 			clear_bit(IREQ_PENDING_ABORT, &ireq->flags);
898726980d5SJeff Skirvin 		/* If the request is only waiting on the remote device
899726980d5SJeff Skirvin 		 * suspension, return SUCCESS so the caller will wait too.
90039ea2c5bSJeff Skirvin 		 */
901726980d5SJeff Skirvin 		return SCI_SUCCESS;
902e301370aSEdmund Nadolski 	case SCI_REQ_COMPLETED:
903f00e6ba4SDan Williams 	default:
904d9dcb4baSDan Williams 		dev_warn(&ireq->owning_controller->pdev->dev,
905f1f52e75SDan Williams 			 "%s: SCIC IO Request requested to abort while in wrong "
906726980d5SJeff Skirvin 			 "state %d\n", __func__, ireq->sm.current_state_id);
907f00e6ba4SDan Williams 		break;
908f00e6ba4SDan Williams 	}
909f1f52e75SDan Williams 
910f1f52e75SDan Williams 	return SCI_FAILURE_INVALID_STATE;
911f1f52e75SDan Williams }
912f1f52e75SDan Williams 
sci_request_complete(struct isci_request * ireq)91389a7301fSDan Williams enum sci_status sci_request_complete(struct isci_request *ireq)
91479e2b6b2SDan Williams {
91579e2b6b2SDan Williams 	enum sci_base_request_states state;
916d9dcb4baSDan Williams 	struct isci_host *ihost = ireq->owning_controller;
91779e2b6b2SDan Williams 
9185076a1a9SDan Williams 	state = ireq->sm.current_state_id;
919e301370aSEdmund Nadolski 	if (WARN_ONCE(state != SCI_REQ_COMPLETED,
920d7a0ccddSDan Williams 		      "isci: request completion from wrong state (%s)\n",
921d7a0ccddSDan Williams 		      req_state_name(state)))
92279e2b6b2SDan Williams 		return SCI_FAILURE_INVALID_STATE;
92379e2b6b2SDan Williams 
9245076a1a9SDan Williams 	if (ireq->saved_rx_frame_index != SCU_INVALID_FRAME_INDEX)
92589a7301fSDan Williams 		sci_controller_release_frame(ihost,
9265076a1a9SDan Williams 						  ireq->saved_rx_frame_index);
92779e2b6b2SDan Williams 
92879e2b6b2SDan Williams 	/* XXX can we just stop the machine and remove the 'final' state? */
9295076a1a9SDan Williams 	sci_change_state(&ireq->sm, SCI_REQ_FINAL);
93079e2b6b2SDan Williams 	return SCI_SUCCESS;
93179e2b6b2SDan Williams }
93279e2b6b2SDan Williams 
sci_io_request_event_handler(struct isci_request * ireq,u32 event_code)93389a7301fSDan Williams enum sci_status sci_io_request_event_handler(struct isci_request *ireq,
934f1f52e75SDan Williams 						  u32 event_code)
935f1f52e75SDan Williams {
93679e2b6b2SDan Williams 	enum sci_base_request_states state;
937d9dcb4baSDan Williams 	struct isci_host *ihost = ireq->owning_controller;
938f1f52e75SDan Williams 
9395076a1a9SDan Williams 	state = ireq->sm.current_state_id;
94079e2b6b2SDan Williams 
941e301370aSEdmund Nadolski 	if (state != SCI_REQ_STP_PIO_DATA_IN) {
942d7a0ccddSDan Williams 		dev_warn(&ihost->pdev->dev, "%s: (%x) in wrong state %s\n",
943d7a0ccddSDan Williams 			 __func__, event_code, req_state_name(state));
944f1f52e75SDan Williams 
945f1f52e75SDan Williams 		return SCI_FAILURE_INVALID_STATE;
9466f231ddaSDan Williams 	}
9476f231ddaSDan Williams 
94879e2b6b2SDan Williams 	switch (scu_get_event_specifier(event_code)) {
94979e2b6b2SDan Williams 	case SCU_TASK_DONE_CRC_ERR << SCU_EVENT_SPECIFIC_CODE_SHIFT:
95079e2b6b2SDan Williams 		/* We are waiting for data and the SCU has R_ERR the data frame.
95179e2b6b2SDan Williams 		 * Go back to waiting for the D2H Register FIS
95279e2b6b2SDan Williams 		 */
9535076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_WAIT_FRAME);
95479e2b6b2SDan Williams 		return SCI_SUCCESS;
95579e2b6b2SDan Williams 	default:
956d9dcb4baSDan Williams 		dev_err(&ihost->pdev->dev,
95779e2b6b2SDan Williams 			"%s: pio request unexpected event %#x\n",
95879e2b6b2SDan Williams 			__func__, event_code);
95979e2b6b2SDan Williams 
96079e2b6b2SDan Williams 		/* TODO Should we fail the PIO request when we get an
96179e2b6b2SDan Williams 		 * unexpected event?
96279e2b6b2SDan Williams 		 */
96379e2b6b2SDan Williams 		return SCI_FAILURE;
96479e2b6b2SDan Williams 	}
96579e2b6b2SDan Williams }
96679e2b6b2SDan Williams 
967f1f52e75SDan Williams /*
968f1f52e75SDan Williams  * This function copies response data for requests returning response data
969f1f52e75SDan Williams  *    instead of sense data.
970f1f52e75SDan Williams  * @sci_req: This parameter specifies the request object for which to copy
971f1f52e75SDan Williams  *    the response data.
972f1f52e75SDan Williams  */
sci_io_request_copy_response(struct isci_request * ireq)97389a7301fSDan Williams static void sci_io_request_copy_response(struct isci_request *ireq)
974f1f52e75SDan Williams {
975f1f52e75SDan Williams 	void *resp_buf;
976f1f52e75SDan Williams 	u32 len;
977f1f52e75SDan Williams 	struct ssp_response_iu *ssp_response;
978f1f52e75SDan Williams 	struct isci_tmf *isci_tmf = isci_request_access_tmf(ireq);
979f1f52e75SDan Williams 
9805076a1a9SDan Williams 	ssp_response = &ireq->ssp.rsp;
981f1f52e75SDan Williams 
982f1f52e75SDan Williams 	resp_buf = &isci_tmf->resp.resp_iu;
983f1f52e75SDan Williams 
984f1f52e75SDan Williams 	len = min_t(u32,
985f1f52e75SDan Williams 		    SSP_RESP_IU_MAX_SIZE,
986f1f52e75SDan Williams 		    be32_to_cpu(ssp_response->response_data_len));
987f1f52e75SDan Williams 
988f1f52e75SDan Williams 	memcpy(resp_buf, ssp_response->resp_data, len);
989f1f52e75SDan Williams }
990f1f52e75SDan Williams 
991e301370aSEdmund Nadolski static enum sci_status
request_started_state_tc_event(struct isci_request * ireq,u32 completion_code)9925076a1a9SDan Williams request_started_state_tc_event(struct isci_request *ireq,
993f1f52e75SDan Williams 			       u32 completion_code)
994f1f52e75SDan Williams {
995f1f52e75SDan Williams 	struct ssp_response_iu *resp_iu;
996a7e255a3SDan Williams 	u8 datapres;
997f1f52e75SDan Williams 
998a7e255a3SDan Williams 	/* TODO: Any SDMA return code of other than 0 is bad decode 0x003C0000
999a7e255a3SDan Williams 	 * to determine SDMA status
1000f1f52e75SDan Williams 	 */
1001f1f52e75SDan Williams 	switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
1002f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
100334a99158SDan Williams 		ireq->scu_status = SCU_TASK_DONE_GOOD;
100434a99158SDan Williams 		ireq->sci_status = SCI_SUCCESS;
1005f1f52e75SDan Williams 		break;
1006a7e255a3SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_EARLY_RESP): {
1007a7e255a3SDan Williams 		/* There are times when the SCU hardware will return an early
1008f1f52e75SDan Williams 		 * response because the io request specified more data than is
1009f1f52e75SDan Williams 		 * returned by the target device (mode pages, inquiry data,
1010f1f52e75SDan Williams 		 * etc.).  We must check the response stats to see if this is
1011f1f52e75SDan Williams 		 * truly a failed request or a good request that just got
1012f1f52e75SDan Williams 		 * completed early.
1013f1f52e75SDan Williams 		 */
10145076a1a9SDan Williams 		struct ssp_response_iu *resp = &ireq->ssp.rsp;
1015f1f52e75SDan Williams 		ssize_t word_cnt = SSP_RESP_IU_MAX_SIZE / sizeof(u32);
1016f1f52e75SDan Williams 
10175076a1a9SDan Williams 		sci_swab32_cpy(&ireq->ssp.rsp,
10185076a1a9SDan Williams 			       &ireq->ssp.rsp,
1019f1f52e75SDan Williams 			       word_cnt);
1020f1f52e75SDan Williams 
1021f1f52e75SDan Williams 		if (resp->status == 0) {
102234a99158SDan Williams 			ireq->scu_status = SCU_TASK_DONE_GOOD;
102334a99158SDan Williams 			ireq->sci_status = SCI_SUCCESS_IO_DONE_EARLY;
1024f1f52e75SDan Williams 		} else {
102534a99158SDan Williams 			ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
102634a99158SDan Williams 			ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
1027f1f52e75SDan Williams 		}
1028f1f52e75SDan Williams 		break;
1029a7e255a3SDan Williams 	}
1030a7e255a3SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CHECK_RESPONSE): {
1031f1f52e75SDan Williams 		ssize_t word_cnt = SSP_RESP_IU_MAX_SIZE / sizeof(u32);
1032f1f52e75SDan Williams 
10335076a1a9SDan Williams 		sci_swab32_cpy(&ireq->ssp.rsp,
10345076a1a9SDan Williams 			       &ireq->ssp.rsp,
1035f1f52e75SDan Williams 			       word_cnt);
1036f1f52e75SDan Williams 
103734a99158SDan Williams 		ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
103834a99158SDan Williams 		ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
1039f1f52e75SDan Williams 		break;
1040f1f52e75SDan Williams 	}
1041f1f52e75SDan Williams 
1042f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_RESP_LEN_ERR):
1043a7e255a3SDan Williams 		/* TODO With TASK_DONE_RESP_LEN_ERR is the response frame
1044f1f52e75SDan Williams 		 * guaranteed to be received before this completion status is
1045f1f52e75SDan Williams 		 * posted?
1046f1f52e75SDan Williams 		 */
10475076a1a9SDan Williams 		resp_iu = &ireq->ssp.rsp;
1048f1f52e75SDan Williams 		datapres = resp_iu->datapres;
1049f1f52e75SDan Williams 
10501d6049a3SJohn Garry 		if (datapres == SAS_DATAPRES_RESPONSE_DATA ||
10511d6049a3SJohn Garry 		    datapres == SAS_DATAPRES_SENSE_DATA) {
105234a99158SDan Williams 			ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
105334a99158SDan Williams 			ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
105434a99158SDan Williams 		} else {
105534a99158SDan Williams 			ireq->scu_status = SCU_TASK_DONE_GOOD;
105634a99158SDan Williams 			ireq->sci_status = SCI_SUCCESS;
105734a99158SDan Williams 		}
1058f1f52e75SDan Williams 		break;
1059f1f52e75SDan Williams 	/* only stp device gets suspended. */
1060f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_ACK_NAK_TO):
1061f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_PERR):
1062f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_NAK_ERR):
1063f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_DATA_LEN_ERR):
1064f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_ABORT_ERR):
1065f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_XR_WD_LEN):
1066f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_MAX_PLD_ERR):
1067f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_RESP):
1068f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_SDBFIS):
1069f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR):
1070f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDB_ERR):
1071c79dd80dSDan Williams 		if (ireq->protocol == SAS_PROTOCOL_STP) {
107234a99158SDan Williams 			ireq->scu_status = SCU_GET_COMPLETION_TL_STATUS(completion_code) >>
107334a99158SDan Williams 					   SCU_COMPLETION_TL_STATUS_SHIFT;
107434a99158SDan Williams 			ireq->sci_status = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED;
1075f1f52e75SDan Williams 		} else {
107634a99158SDan Williams 			ireq->scu_status = SCU_GET_COMPLETION_TL_STATUS(completion_code) >>
107734a99158SDan Williams 					   SCU_COMPLETION_TL_STATUS_SHIFT;
107834a99158SDan Williams 			ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
1079f1f52e75SDan Williams 		}
1080f1f52e75SDan Williams 		break;
1081f1f52e75SDan Williams 
1082f1f52e75SDan Williams 	/* both stp/ssp device gets suspended */
1083f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LF_ERR):
1084f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_WRONG_DESTINATION):
1085f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1):
1086f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2):
1087f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3):
1088f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_BAD_DESTINATION):
1089f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_ZONE_VIOLATION):
1090f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY):
1091f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED):
1092f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED):
109334a99158SDan Williams 		ireq->scu_status = SCU_GET_COMPLETION_TL_STATUS(completion_code) >>
109434a99158SDan Williams 				   SCU_COMPLETION_TL_STATUS_SHIFT;
109534a99158SDan Williams 		ireq->sci_status = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED;
1096f1f52e75SDan Williams 		break;
1097f1f52e75SDan Williams 
1098f1f52e75SDan Williams 	/* neither ssp nor stp gets suspended. */
1099f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_NAK_CMD_ERR):
1100f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_XR):
1101f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_XR_IU_LEN_ERR):
1102f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDMA_ERR):
1103f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_OFFSET_ERR):
1104f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_EXCESS_DATA):
1105f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR):
1106f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR):
1107f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR):
1108f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR):
1109f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_DATA):
1110f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_OPEN_FAIL):
1111f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_VIIT_ENTRY_NV):
1112f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_IIT_ENTRY_NV):
1113f1f52e75SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_RNCNV_OUTBOUND):
1114f1f52e75SDan Williams 	default:
111534a99158SDan Williams 		ireq->scu_status = SCU_GET_COMPLETION_TL_STATUS(completion_code) >>
111634a99158SDan Williams 				   SCU_COMPLETION_TL_STATUS_SHIFT;
111734a99158SDan Williams 		ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
1118f1f52e75SDan Williams 		break;
1119f1f52e75SDan Williams 	}
1120f1f52e75SDan Williams 
1121f1f52e75SDan Williams 	/*
1122f1f52e75SDan Williams 	 * TODO: This is probably wrong for ACK/NAK timeout conditions
1123f1f52e75SDan Williams 	 */
1124f1f52e75SDan Williams 
1125f1f52e75SDan Williams 	/* In all cases we will treat this as the completion of the IO req. */
11265076a1a9SDan Williams 	sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
1127f1f52e75SDan Williams 	return SCI_SUCCESS;
1128f1f52e75SDan Williams }
1129f1f52e75SDan Williams 
1130e301370aSEdmund Nadolski static enum sci_status
request_aborting_state_tc_event(struct isci_request * ireq,u32 completion_code)11315076a1a9SDan Williams request_aborting_state_tc_event(struct isci_request *ireq,
1132f1f52e75SDan Williams 				u32 completion_code)
1133f1f52e75SDan Williams {
1134f1f52e75SDan Williams 	switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
1135f1f52e75SDan Williams 	case (SCU_TASK_DONE_GOOD << SCU_COMPLETION_TL_STATUS_SHIFT):
1136f1f52e75SDan Williams 	case (SCU_TASK_DONE_TASK_ABORT << SCU_COMPLETION_TL_STATUS_SHIFT):
113734a99158SDan Williams 		ireq->scu_status = SCU_TASK_DONE_TASK_ABORT;
113834a99158SDan Williams 		ireq->sci_status = SCI_FAILURE_IO_TERMINATED;
11395076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
1140f1f52e75SDan Williams 		break;
11416f231ddaSDan Williams 
1142f1f52e75SDan Williams 	default:
1143a7e255a3SDan Williams 		/* Unless we get some strange error wait for the task abort to complete
1144a7e255a3SDan Williams 		 * TODO: Should there be a state change for this completion?
1145a7e255a3SDan Williams 		 */
1146f1f52e75SDan Williams 		break;
114767ea838dSDan Williams 	}
11486f231ddaSDan Williams 
1149f1f52e75SDan Williams 	return SCI_SUCCESS;
115067ea838dSDan Williams }
11516f231ddaSDan Williams 
ssp_task_request_await_tc_event(struct isci_request * ireq,u32 completion_code)11525076a1a9SDan Williams static enum sci_status ssp_task_request_await_tc_event(struct isci_request *ireq,
1153f139303dSDan Williams 						       u32 completion_code)
1154f139303dSDan Williams {
1155f139303dSDan Williams 	switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
1156f139303dSDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
115734a99158SDan Williams 		ireq->scu_status = SCU_TASK_DONE_GOOD;
115834a99158SDan Williams 		ireq->sci_status = SCI_SUCCESS;
11595076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_TASK_WAIT_TC_RESP);
1160f139303dSDan Williams 		break;
1161f139303dSDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_ACK_NAK_TO):
1162a7e255a3SDan Williams 		/* Currently, the decision is to simply allow the task request
1163a7e255a3SDan Williams 		 * to timeout if the task IU wasn't received successfully.
1164a7e255a3SDan Williams 		 * There is a potential for receiving multiple task responses if
1165a7e255a3SDan Williams 		 * we decide to send the task IU again.
1166a7e255a3SDan Williams 		 */
1167d9dcb4baSDan Williams 		dev_warn(&ireq->owning_controller->pdev->dev,
1168f139303dSDan Williams 			 "%s: TaskRequest:0x%p CompletionCode:%x - "
11695076a1a9SDan Williams 			 "ACK/NAK timeout\n", __func__, ireq,
1170f139303dSDan Williams 			 completion_code);
1171f139303dSDan Williams 
11725076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_TASK_WAIT_TC_RESP);
1173f139303dSDan Williams 		break;
1174f139303dSDan Williams 	default:
1175e301370aSEdmund Nadolski 		/*
1176e301370aSEdmund Nadolski 		 * All other completion status cause the IO to be complete.
1177e301370aSEdmund Nadolski 		 * If a NAK was received, then it is up to the user to retry
1178e301370aSEdmund Nadolski 		 * the request.
1179a7e255a3SDan Williams 		 */
118034a99158SDan Williams 		ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
118134a99158SDan Williams 		ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
11825076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
1183f139303dSDan Williams 		break;
1184f139303dSDan Williams 	}
1185f139303dSDan Williams 
1186f139303dSDan Williams 	return SCI_SUCCESS;
1187f139303dSDan Williams }
1188f139303dSDan Williams 
1189e301370aSEdmund Nadolski static enum sci_status
smp_request_await_response_tc_event(struct isci_request * ireq,u32 completion_code)11905076a1a9SDan Williams smp_request_await_response_tc_event(struct isci_request *ireq,
1191c72086e3SDan Williams 				    u32 completion_code)
1192c72086e3SDan Williams {
1193c72086e3SDan Williams 	switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
1194c72086e3SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
1195a7e255a3SDan Williams 		/* In the AWAIT RESPONSE state, any TC completion is
1196a7e255a3SDan Williams 		 * unexpected.  but if the TC has success status, we
1197a7e255a3SDan Williams 		 * complete the IO anyway.
1198a7e255a3SDan Williams 		 */
119934a99158SDan Williams 		ireq->scu_status = SCU_TASK_DONE_GOOD;
120034a99158SDan Williams 		ireq->sci_status = SCI_SUCCESS;
12015076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
1202c72086e3SDan Williams 		break;
1203c72086e3SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR):
1204c72086e3SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR):
1205c72086e3SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR):
1206c72086e3SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR):
1207a7e255a3SDan Williams 		/* These status has been seen in a specific LSI
1208a7e255a3SDan Williams 		 * expander, which sometimes is not able to send smp
1209a7e255a3SDan Williams 		 * response within 2 ms. This causes our hardware break
1210a7e255a3SDan Williams 		 * the connection and set TC completion with one of
1211a7e255a3SDan Williams 		 * these SMP_XXX_XX_ERR status. For these type of error,
1212d9dcb4baSDan Williams 		 * we ask ihost user to retry the request.
1213a7e255a3SDan Williams 		 */
121434a99158SDan Williams 		ireq->scu_status = SCU_TASK_DONE_SMP_RESP_TO_ERR;
121534a99158SDan Williams 		ireq->sci_status = SCI_FAILURE_RETRY_REQUIRED;
12165076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
1217c72086e3SDan Williams 		break;
1218c72086e3SDan Williams 	default:
1219a7e255a3SDan Williams 		/* All other completion status cause the IO to be complete.  If a NAK
1220a7e255a3SDan Williams 		 * was received, then it is up to the user to retry the request
1221a7e255a3SDan Williams 		 */
122234a99158SDan Williams 		ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
122334a99158SDan Williams 		ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
12245076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
1225c72086e3SDan Williams 		break;
1226c72086e3SDan Williams 	}
1227c72086e3SDan Williams 
1228c72086e3SDan Williams 	return SCI_SUCCESS;
1229c72086e3SDan Williams }
1230c72086e3SDan Williams 
1231e301370aSEdmund Nadolski static enum sci_status
smp_request_await_tc_event(struct isci_request * ireq,u32 completion_code)12325076a1a9SDan Williams smp_request_await_tc_event(struct isci_request *ireq,
1233c72086e3SDan Williams 			   u32 completion_code)
1234c72086e3SDan Williams {
1235c72086e3SDan Williams 	switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
1236c72086e3SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
123734a99158SDan Williams 		ireq->scu_status = SCU_TASK_DONE_GOOD;
123834a99158SDan Williams 		ireq->sci_status = SCI_SUCCESS;
12395076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
1240c72086e3SDan Williams 		break;
1241c72086e3SDan Williams 	default:
1242a7e255a3SDan Williams 		/* All other completion status cause the IO to be
1243a7e255a3SDan Williams 		 * complete.  If a NAK was received, then it is up to
1244a7e255a3SDan Williams 		 * the user to retry the request.
1245a7e255a3SDan Williams 		 */
124634a99158SDan Williams 		ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
124734a99158SDan Williams 		ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
12485076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
1249c72086e3SDan Williams 		break;
1250c72086e3SDan Williams 	}
1251c72086e3SDan Williams 
1252c72086e3SDan Williams 	return SCI_SUCCESS;
1253c72086e3SDan Williams }
1254c72086e3SDan Williams 
pio_sgl_next(struct isci_stp_request * stp_req)1255ba7cb223SDan Williams static struct scu_sgl_element *pio_sgl_next(struct isci_stp_request *stp_req)
12565dec6f4eSDan Williams {
1257312e0c24SDan Williams 	struct scu_sgl_element *sgl;
1258312e0c24SDan Williams 	struct scu_sgl_element_pair *sgl_pair;
12595076a1a9SDan Williams 	struct isci_request *ireq = to_ireq(stp_req);
1260ba7cb223SDan Williams 	struct isci_stp_pio_sgl *pio_sgl = &stp_req->sgl;
12615dec6f4eSDan Williams 
12625076a1a9SDan Williams 	sgl_pair = to_sgl_element_pair(ireq, pio_sgl->index);
1263312e0c24SDan Williams 	if (!sgl_pair)
1264312e0c24SDan Williams 		sgl = NULL;
1265ba7cb223SDan Williams 	else if (pio_sgl->set == SCU_SGL_ELEMENT_PAIR_A) {
1266312e0c24SDan Williams 		if (sgl_pair->B.address_lower == 0 &&
1267312e0c24SDan Williams 		    sgl_pair->B.address_upper == 0) {
1268312e0c24SDan Williams 			sgl = NULL;
12695dec6f4eSDan Williams 		} else {
1270ba7cb223SDan Williams 			pio_sgl->set = SCU_SGL_ELEMENT_PAIR_B;
1271312e0c24SDan Williams 			sgl = &sgl_pair->B;
12725dec6f4eSDan Williams 		}
12735dec6f4eSDan Williams 	} else {
1274312e0c24SDan Williams 		if (sgl_pair->next_pair_lower == 0 &&
1275312e0c24SDan Williams 		    sgl_pair->next_pair_upper == 0) {
1276312e0c24SDan Williams 			sgl = NULL;
12775dec6f4eSDan Williams 		} else {
1278ba7cb223SDan Williams 			pio_sgl->index++;
1279ba7cb223SDan Williams 			pio_sgl->set = SCU_SGL_ELEMENT_PAIR_A;
12805076a1a9SDan Williams 			sgl_pair = to_sgl_element_pair(ireq, pio_sgl->index);
1281312e0c24SDan Williams 			sgl = &sgl_pair->A;
12825dec6f4eSDan Williams 		}
12835dec6f4eSDan Williams 	}
12845dec6f4eSDan Williams 
1285312e0c24SDan Williams 	return sgl;
12865dec6f4eSDan Williams }
12875dec6f4eSDan Williams 
1288e301370aSEdmund Nadolski static enum sci_status
stp_request_non_data_await_h2d_tc_event(struct isci_request * ireq,u32 completion_code)12895076a1a9SDan Williams stp_request_non_data_await_h2d_tc_event(struct isci_request *ireq,
12905dec6f4eSDan Williams 					u32 completion_code)
12915dec6f4eSDan Williams {
12925dec6f4eSDan Williams 	switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
12935dec6f4eSDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
129434a99158SDan Williams 		ireq->scu_status = SCU_TASK_DONE_GOOD;
129534a99158SDan Williams 		ireq->sci_status = SCI_SUCCESS;
12965076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_STP_NON_DATA_WAIT_D2H);
12975dec6f4eSDan Williams 		break;
12985dec6f4eSDan Williams 
12995dec6f4eSDan Williams 	default:
1300a7e255a3SDan Williams 		/* All other completion status cause the IO to be
1301a7e255a3SDan Williams 		 * complete.  If a NAK was received, then it is up to
1302a7e255a3SDan Williams 		 * the user to retry the request.
1303a7e255a3SDan Williams 		 */
130434a99158SDan Williams 		ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
130534a99158SDan Williams 		ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
13065076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
13075dec6f4eSDan Williams 		break;
13085dec6f4eSDan Williams 	}
13095dec6f4eSDan Williams 
13105dec6f4eSDan Williams 	return SCI_SUCCESS;
13115dec6f4eSDan Williams }
13125dec6f4eSDan Williams 
13135dec6f4eSDan Williams #define SCU_MAX_FRAME_BUFFER_SIZE  0x400  /* 1K is the maximum SCU frame data payload */
13145dec6f4eSDan Williams 
13155dec6f4eSDan Williams /* transmit DATA_FIS from (current sgl + offset) for input
13165dec6f4eSDan Williams  * parameter length. current sgl and offset is alreay stored in the IO request
13175dec6f4eSDan Williams  */
sci_stp_request_pio_data_out_trasmit_data_frame(struct isci_request * ireq,u32 length)131889a7301fSDan Williams static enum sci_status sci_stp_request_pio_data_out_trasmit_data_frame(
13195076a1a9SDan Williams 	struct isci_request *ireq,
13205dec6f4eSDan Williams 	u32 length)
13215dec6f4eSDan Williams {
13225076a1a9SDan Williams 	struct isci_stp_request *stp_req = &ireq->stp.req;
13235076a1a9SDan Williams 	struct scu_task_context *task_context = ireq->tc;
1324312e0c24SDan Williams 	struct scu_sgl_element_pair *sgl_pair;
13255dec6f4eSDan Williams 	struct scu_sgl_element *current_sgl;
13265dec6f4eSDan Williams 
13275dec6f4eSDan Williams 	/* Recycle the TC and reconstruct it for sending out DATA FIS containing
13285dec6f4eSDan Williams 	 * for the data from current_sgl+offset for the input length
13295dec6f4eSDan Williams 	 */
13305076a1a9SDan Williams 	sgl_pair = to_sgl_element_pair(ireq, stp_req->sgl.index);
1331ba7cb223SDan Williams 	if (stp_req->sgl.set == SCU_SGL_ELEMENT_PAIR_A)
1332312e0c24SDan Williams 		current_sgl = &sgl_pair->A;
13335dec6f4eSDan Williams 	else
1334312e0c24SDan Williams 		current_sgl = &sgl_pair->B;
13355dec6f4eSDan Williams 
13365dec6f4eSDan Williams 	/* update the TC */
13375dec6f4eSDan Williams 	task_context->command_iu_upper = current_sgl->address_upper;
13385dec6f4eSDan Williams 	task_context->command_iu_lower = current_sgl->address_lower;
13395dec6f4eSDan Williams 	task_context->transfer_length_bytes = length;
13405dec6f4eSDan Williams 	task_context->type.stp.fis_type = FIS_DATA;
13415dec6f4eSDan Williams 
13425dec6f4eSDan Williams 	/* send the new TC out. */
134389a7301fSDan Williams 	return sci_controller_continue_io(ireq);
13445dec6f4eSDan Williams }
13455dec6f4eSDan Williams 
sci_stp_request_pio_data_out_transmit_data(struct isci_request * ireq)134689a7301fSDan Williams static enum sci_status sci_stp_request_pio_data_out_transmit_data(struct isci_request *ireq)
13475dec6f4eSDan Williams {
13485076a1a9SDan Williams 	struct isci_stp_request *stp_req = &ireq->stp.req;
1349312e0c24SDan Williams 	struct scu_sgl_element_pair *sgl_pair;
1350b50102d3SDan Williams 	enum sci_status status = SCI_SUCCESS;
1351ba7cb223SDan Williams 	struct scu_sgl_element *sgl;
1352ba7cb223SDan Williams 	u32 offset;
1353ba7cb223SDan Williams 	u32 len = 0;
13545dec6f4eSDan Williams 
1355ba7cb223SDan Williams 	offset = stp_req->sgl.offset;
13565076a1a9SDan Williams 	sgl_pair = to_sgl_element_pair(ireq, stp_req->sgl.index);
1357312e0c24SDan Williams 	if (WARN_ONCE(!sgl_pair, "%s: null sgl element", __func__))
1358312e0c24SDan Williams 		return SCI_FAILURE;
13595dec6f4eSDan Williams 
1360ba7cb223SDan Williams 	if (stp_req->sgl.set == SCU_SGL_ELEMENT_PAIR_A) {
1361ba7cb223SDan Williams 		sgl = &sgl_pair->A;
1362ba7cb223SDan Williams 		len = sgl_pair->A.length - offset;
13635dec6f4eSDan Williams 	} else {
1364ba7cb223SDan Williams 		sgl = &sgl_pair->B;
1365ba7cb223SDan Williams 		len = sgl_pair->B.length - offset;
13665dec6f4eSDan Williams 	}
13675dec6f4eSDan Williams 
1368ba7cb223SDan Williams 	if (stp_req->pio_len == 0)
1369ba7cb223SDan Williams 		return SCI_SUCCESS;
13705dec6f4eSDan Williams 
1371ba7cb223SDan Williams 	if (stp_req->pio_len >= len) {
137289a7301fSDan Williams 		status = sci_stp_request_pio_data_out_trasmit_data_frame(ireq, len);
1373ba7cb223SDan Williams 		if (status != SCI_SUCCESS)
1374ba7cb223SDan Williams 			return status;
1375ba7cb223SDan Williams 		stp_req->pio_len -= len;
13765dec6f4eSDan Williams 
1377ba7cb223SDan Williams 		/* update the current sgl, offset and save for future */
1378ba7cb223SDan Williams 		sgl = pio_sgl_next(stp_req);
1379ba7cb223SDan Williams 		offset = 0;
1380ba7cb223SDan Williams 	} else if (stp_req->pio_len < len) {
138189a7301fSDan Williams 		sci_stp_request_pio_data_out_trasmit_data_frame(ireq, stp_req->pio_len);
1382ba7cb223SDan Williams 
13835dec6f4eSDan Williams 		/* Sgl offset will be adjusted and saved for future */
1384ba7cb223SDan Williams 		offset += stp_req->pio_len;
1385ba7cb223SDan Williams 		sgl->address_lower += stp_req->pio_len;
1386ba7cb223SDan Williams 		stp_req->pio_len = 0;
13875dec6f4eSDan Williams 	}
13885dec6f4eSDan Williams 
1389ba7cb223SDan Williams 	stp_req->sgl.offset = offset;
13905dec6f4eSDan Williams 
13915dec6f4eSDan Williams 	return status;
13925dec6f4eSDan Williams }
13935dec6f4eSDan Williams 
13945dec6f4eSDan Williams /**
1395db35a083SLee Jones  * sci_stp_request_pio_data_in_copy_data_buffer()
1396db35a083SLee Jones  * @stp_req: The request that is used for the SGL processing.
1397db35a083SLee Jones  * @data_buf: The buffer of data to be copied.
1398db35a083SLee Jones  * @len: The length of the data transfer.
13995dec6f4eSDan Williams  *
1400f5f44c6fSColin Ian King  * Copy the data from the buffer for the length specified to the IO request SGL
14015dec6f4eSDan Williams  * specified data region. enum sci_status
14025dec6f4eSDan Williams  */
14035dec6f4eSDan Williams static enum sci_status
sci_stp_request_pio_data_in_copy_data_buffer(struct isci_stp_request * stp_req,u8 * data_buf,u32 len)140489a7301fSDan Williams sci_stp_request_pio_data_in_copy_data_buffer(struct isci_stp_request *stp_req,
14055dec6f4eSDan Williams 					     u8 *data_buf, u32 len)
14065dec6f4eSDan Williams {
14075dec6f4eSDan Williams 	struct isci_request *ireq;
14085dec6f4eSDan Williams 	u8 *src_addr;
14095dec6f4eSDan Williams 	int copy_len;
14105dec6f4eSDan Williams 	struct sas_task *task;
14115dec6f4eSDan Williams 	struct scatterlist *sg;
14125dec6f4eSDan Williams 	void *kaddr;
14135dec6f4eSDan Williams 	int total_len = len;
14145dec6f4eSDan Williams 
14155076a1a9SDan Williams 	ireq = to_ireq(stp_req);
14165dec6f4eSDan Williams 	task = isci_request_access_task(ireq);
14175dec6f4eSDan Williams 	src_addr = data_buf;
14185dec6f4eSDan Williams 
14195dec6f4eSDan Williams 	if (task->num_scatter > 0) {
14205dec6f4eSDan Williams 		sg = task->scatter;
14215dec6f4eSDan Williams 
14225dec6f4eSDan Williams 		while (total_len > 0) {
14235dec6f4eSDan Williams 			struct page *page = sg_page(sg);
14245dec6f4eSDan Williams 
14255dec6f4eSDan Williams 			copy_len = min_t(int, total_len, sg_dma_len(sg));
142677dfce07SCong Wang 			kaddr = kmap_atomic(page);
14275dec6f4eSDan Williams 			memcpy(kaddr + sg->offset, src_addr, copy_len);
142877dfce07SCong Wang 			kunmap_atomic(kaddr);
14295dec6f4eSDan Williams 			total_len -= copy_len;
14305dec6f4eSDan Williams 			src_addr += copy_len;
14315dec6f4eSDan Williams 			sg = sg_next(sg);
14325dec6f4eSDan Williams 		}
14335dec6f4eSDan Williams 	} else {
14345dec6f4eSDan Williams 		BUG_ON(task->total_xfer_len < total_len);
14355dec6f4eSDan Williams 		memcpy(task->scatter, src_addr, total_len);
14365dec6f4eSDan Williams 	}
14375dec6f4eSDan Williams 
14385dec6f4eSDan Williams 	return SCI_SUCCESS;
14395dec6f4eSDan Williams }
14405dec6f4eSDan Williams 
14415dec6f4eSDan Williams /**
1442db35a083SLee Jones  * sci_stp_request_pio_data_in_copy_data()
1443db35a083SLee Jones  * @stp_req: The PIO DATA IN request that is to receive the data.
14445dec6f4eSDan Williams  * @data_buffer: The buffer to copy from.
14455dec6f4eSDan Williams  *
14465dec6f4eSDan Williams  * Copy the data buffer to the io request data region. enum sci_status
14475dec6f4eSDan Williams  */
sci_stp_request_pio_data_in_copy_data(struct isci_stp_request * stp_req,u8 * data_buffer)144889a7301fSDan Williams static enum sci_status sci_stp_request_pio_data_in_copy_data(
1449ba7cb223SDan Williams 	struct isci_stp_request *stp_req,
14505dec6f4eSDan Williams 	u8 *data_buffer)
14515dec6f4eSDan Williams {
14525dec6f4eSDan Williams 	enum sci_status status;
14535dec6f4eSDan Williams 
14545dec6f4eSDan Williams 	/*
14555dec6f4eSDan Williams 	 * If there is less than 1K remaining in the transfer request
14565dec6f4eSDan Williams 	 * copy just the data for the transfer */
1457ba7cb223SDan Williams 	if (stp_req->pio_len < SCU_MAX_FRAME_BUFFER_SIZE) {
145889a7301fSDan Williams 		status = sci_stp_request_pio_data_in_copy_data_buffer(
1459ba7cb223SDan Williams 			stp_req, data_buffer, stp_req->pio_len);
14605dec6f4eSDan Williams 
14615dec6f4eSDan Williams 		if (status == SCI_SUCCESS)
1462ba7cb223SDan Williams 			stp_req->pio_len = 0;
14635dec6f4eSDan Williams 	} else {
14645dec6f4eSDan Williams 		/* We are transfering the whole frame so copy */
146589a7301fSDan Williams 		status = sci_stp_request_pio_data_in_copy_data_buffer(
1466ba7cb223SDan Williams 			stp_req, data_buffer, SCU_MAX_FRAME_BUFFER_SIZE);
14675dec6f4eSDan Williams 
14685dec6f4eSDan Williams 		if (status == SCI_SUCCESS)
1469ba7cb223SDan Williams 			stp_req->pio_len -= SCU_MAX_FRAME_BUFFER_SIZE;
14705dec6f4eSDan Williams 	}
14715dec6f4eSDan Williams 
14725dec6f4eSDan Williams 	return status;
14735dec6f4eSDan Williams }
14745dec6f4eSDan Williams 
1475e301370aSEdmund Nadolski static enum sci_status
stp_request_pio_await_h2d_completion_tc_event(struct isci_request * ireq,u32 completion_code)14765076a1a9SDan Williams stp_request_pio_await_h2d_completion_tc_event(struct isci_request *ireq,
14775dec6f4eSDan Williams 					      u32 completion_code)
14785dec6f4eSDan Williams {
14795dec6f4eSDan Williams 	switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
14805dec6f4eSDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
148134a99158SDan Williams 		ireq->scu_status = SCU_TASK_DONE_GOOD;
148234a99158SDan Williams 		ireq->sci_status = SCI_SUCCESS;
14835076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_WAIT_FRAME);
14845dec6f4eSDan Williams 		break;
14855dec6f4eSDan Williams 
14865dec6f4eSDan Williams 	default:
1487a7e255a3SDan Williams 		/* All other completion status cause the IO to be
1488a7e255a3SDan Williams 		 * complete.  If a NAK was received, then it is up to
1489a7e255a3SDan Williams 		 * the user to retry the request.
1490a7e255a3SDan Williams 		 */
149134a99158SDan Williams 		ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
149234a99158SDan Williams 		ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
14935076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
14945dec6f4eSDan Williams 		break;
14955dec6f4eSDan Williams 	}
14965dec6f4eSDan Williams 
149770ae13abSYang Li 	return SCI_SUCCESS;
14985dec6f4eSDan Williams }
14995dec6f4eSDan Williams 
1500e301370aSEdmund Nadolski static enum sci_status
pio_data_out_tx_done_tc_event(struct isci_request * ireq,u32 completion_code)15015076a1a9SDan Williams pio_data_out_tx_done_tc_event(struct isci_request *ireq,
15025dec6f4eSDan Williams 			      u32 completion_code)
15035dec6f4eSDan Williams {
15045dec6f4eSDan Williams 	enum sci_status status = SCI_SUCCESS;
15055dec6f4eSDan Williams 	bool all_frames_transferred = false;
15065076a1a9SDan Williams 	struct isci_stp_request *stp_req = &ireq->stp.req;
15075dec6f4eSDan Williams 
15085dec6f4eSDan Williams 	switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
15095dec6f4eSDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
15105dec6f4eSDan Williams 		/* Transmit data */
1511ba7cb223SDan Williams 		if (stp_req->pio_len != 0) {
151289a7301fSDan Williams 			status = sci_stp_request_pio_data_out_transmit_data(ireq);
15135dec6f4eSDan Williams 			if (status == SCI_SUCCESS) {
1514ba7cb223SDan Williams 				if (stp_req->pio_len == 0)
15155dec6f4eSDan Williams 					all_frames_transferred = true;
15165dec6f4eSDan Williams 			}
1517ba7cb223SDan Williams 		} else if (stp_req->pio_len == 0) {
15185dec6f4eSDan Williams 			/*
15195dec6f4eSDan Williams 			 * this will happen if the all data is written at the
15205dec6f4eSDan Williams 			 * first time after the pio setup fis is received
15215dec6f4eSDan Williams 			 */
15225dec6f4eSDan Williams 			all_frames_transferred  = true;
15235dec6f4eSDan Williams 		}
15245dec6f4eSDan Williams 
15255dec6f4eSDan Williams 		/* all data transferred. */
15265dec6f4eSDan Williams 		if (all_frames_transferred) {
15275dec6f4eSDan Williams 			/*
1528e301370aSEdmund Nadolski 			 * Change the state to SCI_REQ_STP_PIO_DATA_IN
15295dec6f4eSDan Williams 			 * and wait for PIO_SETUP fis / or D2H REg fis. */
15305076a1a9SDan Williams 			sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_WAIT_FRAME);
15315dec6f4eSDan Williams 		}
15325dec6f4eSDan Williams 		break;
1533e301370aSEdmund Nadolski 
15345dec6f4eSDan Williams 	default:
15355dec6f4eSDan Williams 		/*
1536e301370aSEdmund Nadolski 		 * All other completion status cause the IO to be complete.
1537e301370aSEdmund Nadolski 		 * If a NAK was received, then it is up to the user to retry
1538e301370aSEdmund Nadolski 		 * the request.
1539e301370aSEdmund Nadolski 		 */
154034a99158SDan Williams 		ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
154134a99158SDan Williams 		ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
15425076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
15435dec6f4eSDan Williams 		break;
15445dec6f4eSDan Williams 	}
15455dec6f4eSDan Williams 
15465dec6f4eSDan Williams 	return status;
15475dec6f4eSDan Williams }
15485dec6f4eSDan Williams 
sci_stp_request_udma_general_frame_handler(struct isci_request * ireq,u32 frame_index)154989a7301fSDan Williams static enum sci_status sci_stp_request_udma_general_frame_handler(struct isci_request *ireq,
15505dec6f4eSDan Williams 								       u32 frame_index)
15515dec6f4eSDan Williams {
1552d9dcb4baSDan Williams 	struct isci_host *ihost = ireq->owning_controller;
15535dec6f4eSDan Williams 	struct dev_to_host_fis *frame_header;
15545dec6f4eSDan Williams 	enum sci_status status;
15555dec6f4eSDan Williams 	u32 *frame_buffer;
15565dec6f4eSDan Williams 
155789a7301fSDan Williams 	status = sci_unsolicited_frame_control_get_header(&ihost->uf_control,
15585dec6f4eSDan Williams 							       frame_index,
15595dec6f4eSDan Williams 							       (void **)&frame_header);
15605dec6f4eSDan Williams 
15615dec6f4eSDan Williams 	if ((status == SCI_SUCCESS) &&
15625dec6f4eSDan Williams 	    (frame_header->fis_type == FIS_REGD2H)) {
156389a7301fSDan Williams 		sci_unsolicited_frame_control_get_buffer(&ihost->uf_control,
15645dec6f4eSDan Williams 							      frame_index,
15655dec6f4eSDan Williams 							      (void **)&frame_buffer);
15665dec6f4eSDan Williams 
156789a7301fSDan Williams 		sci_controller_copy_sata_response(&ireq->stp.rsp,
15685dec6f4eSDan Williams 						       frame_header,
15695dec6f4eSDan Williams 						       frame_buffer);
15705dec6f4eSDan Williams 	}
15715dec6f4eSDan Williams 
157289a7301fSDan Williams 	sci_controller_release_frame(ihost, frame_index);
15735dec6f4eSDan Williams 
15745dec6f4eSDan Williams 	return status;
15755dec6f4eSDan Williams }
15765dec6f4eSDan Williams 
process_unsolicited_fis(struct isci_request * ireq,u32 frame_index)1577b50102d3SDan Williams static enum sci_status process_unsolicited_fis(struct isci_request *ireq,
1578b50102d3SDan Williams 					       u32 frame_index)
1579b50102d3SDan Williams {
1580b50102d3SDan Williams 	struct isci_host *ihost = ireq->owning_controller;
1581b50102d3SDan Williams 	enum sci_status status;
1582b50102d3SDan Williams 	struct dev_to_host_fis *frame_header;
1583b50102d3SDan Williams 	u32 *frame_buffer;
1584b50102d3SDan Williams 
1585b50102d3SDan Williams 	status = sci_unsolicited_frame_control_get_header(&ihost->uf_control,
1586b50102d3SDan Williams 							  frame_index,
1587b50102d3SDan Williams 							  (void **)&frame_header);
1588b50102d3SDan Williams 
1589b50102d3SDan Williams 	if (status != SCI_SUCCESS)
1590b50102d3SDan Williams 		return status;
1591b50102d3SDan Williams 
1592b50102d3SDan Williams 	if (frame_header->fis_type != FIS_REGD2H) {
1593b50102d3SDan Williams 		dev_err(&ireq->isci_host->pdev->dev,
1594b50102d3SDan Williams 			"%s ERROR: invalid fis type 0x%X\n",
1595b50102d3SDan Williams 			__func__, frame_header->fis_type);
1596b50102d3SDan Williams 		return SCI_FAILURE;
1597b50102d3SDan Williams 	}
1598b50102d3SDan Williams 
1599b50102d3SDan Williams 	sci_unsolicited_frame_control_get_buffer(&ihost->uf_control,
1600b50102d3SDan Williams 						 frame_index,
1601b50102d3SDan Williams 						 (void **)&frame_buffer);
1602b50102d3SDan Williams 
1603b50102d3SDan Williams 	sci_controller_copy_sata_response(&ireq->stp.rsp,
1604b50102d3SDan Williams 					  (u32 *)frame_header,
1605b50102d3SDan Williams 					  frame_buffer);
1606b50102d3SDan Williams 
1607b50102d3SDan Williams 	/* Frame has been decoded return it to the controller */
1608b50102d3SDan Williams 	sci_controller_release_frame(ihost, frame_index);
1609b50102d3SDan Williams 
1610b50102d3SDan Williams 	return status;
1611b50102d3SDan Williams }
1612b50102d3SDan Williams 
atapi_d2h_reg_frame_handler(struct isci_request * ireq,u32 frame_index)1613b50102d3SDan Williams static enum sci_status atapi_d2h_reg_frame_handler(struct isci_request *ireq,
1614b50102d3SDan Williams 						   u32 frame_index)
1615b50102d3SDan Williams {
1616b50102d3SDan Williams 	struct sas_task *task = isci_request_access_task(ireq);
1617b50102d3SDan Williams 	enum sci_status status;
1618b50102d3SDan Williams 
1619b50102d3SDan Williams 	status = process_unsolicited_fis(ireq, frame_index);
1620b50102d3SDan Williams 
1621b50102d3SDan Williams 	if (status == SCI_SUCCESS) {
1622b50102d3SDan Williams 		if (ireq->stp.rsp.status & ATA_ERR)
1623e9e9a103SNathan Chancellor 			status = SCI_FAILURE_IO_RESPONSE_VALID;
1624b50102d3SDan Williams 	} else {
1625e9e9a103SNathan Chancellor 		status = SCI_FAILURE_IO_RESPONSE_VALID;
1626b50102d3SDan Williams 	}
1627b50102d3SDan Williams 
1628b50102d3SDan Williams 	if (status != SCI_SUCCESS) {
1629b50102d3SDan Williams 		ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
1630b50102d3SDan Williams 		ireq->sci_status = status;
1631b50102d3SDan Williams 	} else {
1632b50102d3SDan Williams 		ireq->scu_status = SCU_TASK_DONE_GOOD;
1633b50102d3SDan Williams 		ireq->sci_status = SCI_SUCCESS;
1634b50102d3SDan Williams 	}
1635b50102d3SDan Williams 
1636b50102d3SDan Williams 	/* the d2h ufi is the end of non-data commands */
1637b50102d3SDan Williams 	if (task->data_dir == DMA_NONE)
1638b50102d3SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
1639b50102d3SDan Williams 
1640b50102d3SDan Williams 	return status;
1641b50102d3SDan Williams }
1642b50102d3SDan Williams 
scu_atapi_reconstruct_raw_frame_task_context(struct isci_request * ireq)1643b50102d3SDan Williams static void scu_atapi_reconstruct_raw_frame_task_context(struct isci_request *ireq)
1644b50102d3SDan Williams {
1645b50102d3SDan Williams 	struct ata_device *dev = sas_to_ata_dev(ireq->target_device->domain_dev);
1646b50102d3SDan Williams 	void *atapi_cdb = ireq->ttype_ptr.io_task_ptr->ata_task.atapi_packet;
1647b50102d3SDan Williams 	struct scu_task_context *task_context = ireq->tc;
1648b50102d3SDan Williams 
1649b50102d3SDan Williams 	/* fill in the SCU Task Context for a DATA fis containing CDB in Raw Frame
1650b50102d3SDan Williams 	 * type. The TC for previous Packet fis was already there, we only need to
1651b50102d3SDan Williams 	 * change the H2D fis content.
1652b50102d3SDan Williams 	 */
1653b50102d3SDan Williams 	memset(&ireq->stp.cmd, 0, sizeof(struct host_to_dev_fis));
1654b50102d3SDan Williams 	memcpy(((u8 *)&ireq->stp.cmd + sizeof(u32)), atapi_cdb, ATAPI_CDB_LEN);
1655b50102d3SDan Williams 	memset(&(task_context->type.stp), 0, sizeof(struct stp_task_context));
1656b50102d3SDan Williams 	task_context->type.stp.fis_type = FIS_DATA;
1657b50102d3SDan Williams 	task_context->transfer_length_bytes = dev->cdb_len;
1658b50102d3SDan Williams }
1659b50102d3SDan Williams 
scu_atapi_construct_task_context(struct isci_request * ireq)1660b50102d3SDan Williams static void scu_atapi_construct_task_context(struct isci_request *ireq)
1661b50102d3SDan Williams {
1662b50102d3SDan Williams 	struct ata_device *dev = sas_to_ata_dev(ireq->target_device->domain_dev);
1663b50102d3SDan Williams 	struct sas_task *task = isci_request_access_task(ireq);
1664b50102d3SDan Williams 	struct scu_task_context *task_context = ireq->tc;
1665b50102d3SDan Williams 	int cdb_len = dev->cdb_len;
1666b50102d3SDan Williams 
1667b50102d3SDan Williams 	/* reference: SSTL 1.13.4.2
1668b50102d3SDan Williams 	 * task_type, sata_direction
1669b50102d3SDan Williams 	 */
1670b50102d3SDan Williams 	if (task->data_dir == DMA_TO_DEVICE) {
1671b50102d3SDan Williams 		task_context->task_type = SCU_TASK_TYPE_PACKET_DMA_OUT;
1672b50102d3SDan Williams 		task_context->sata_direction = 0;
1673b50102d3SDan Williams 	} else {
1674b50102d3SDan Williams 		/* todo: for NO_DATA command, we need to send out raw frame. */
1675b50102d3SDan Williams 		task_context->task_type = SCU_TASK_TYPE_PACKET_DMA_IN;
1676b50102d3SDan Williams 		task_context->sata_direction = 1;
1677b50102d3SDan Williams 	}
1678b50102d3SDan Williams 
1679b50102d3SDan Williams 	memset(&task_context->type.stp, 0, sizeof(task_context->type.stp));
1680b50102d3SDan Williams 	task_context->type.stp.fis_type = FIS_DATA;
1681b50102d3SDan Williams 
1682b50102d3SDan Williams 	memset(&ireq->stp.cmd, 0, sizeof(ireq->stp.cmd));
1683b50102d3SDan Williams 	memcpy(&ireq->stp.cmd.lbal, task->ata_task.atapi_packet, cdb_len);
1684b50102d3SDan Williams 	task_context->ssp_command_iu_length = cdb_len / sizeof(u32);
1685b50102d3SDan Williams 
1686b50102d3SDan Williams 	/* task phase is set to TX_CMD */
1687b50102d3SDan Williams 	task_context->task_phase = 0x1;
1688b50102d3SDan Williams 
1689b50102d3SDan Williams 	/* retry counter */
1690b50102d3SDan Williams 	task_context->stp_retry_count = 0;
1691b50102d3SDan Williams 
1692b50102d3SDan Williams 	/* data transfer size. */
1693b50102d3SDan Williams 	task_context->transfer_length_bytes = task->total_xfer_len;
1694b50102d3SDan Williams 
1695b50102d3SDan Williams 	/* setup sgl */
1696b50102d3SDan Williams 	sci_request_build_sgl(ireq);
1697b50102d3SDan Williams }
1698b50102d3SDan Williams 
1699e301370aSEdmund Nadolski enum sci_status
sci_io_request_frame_handler(struct isci_request * ireq,u32 frame_index)170089a7301fSDan Williams sci_io_request_frame_handler(struct isci_request *ireq,
1701d1c637c3SDan Williams 				  u32 frame_index)
1702d1c637c3SDan Williams {
1703d9dcb4baSDan Williams 	struct isci_host *ihost = ireq->owning_controller;
17045076a1a9SDan Williams 	struct isci_stp_request *stp_req = &ireq->stp.req;
1705d1c637c3SDan Williams 	enum sci_base_request_states state;
1706d1c637c3SDan Williams 	enum sci_status status;
1707d1c637c3SDan Williams 	ssize_t word_cnt;
1708d1c637c3SDan Williams 
17095076a1a9SDan Williams 	state = ireq->sm.current_state_id;
1710d1c637c3SDan Williams 	switch (state)  {
1711e301370aSEdmund Nadolski 	case SCI_REQ_STARTED: {
1712d1c637c3SDan Williams 		struct ssp_frame_hdr ssp_hdr;
1713d1c637c3SDan Williams 		void *frame_header;
1714d1c637c3SDan Williams 
171589a7301fSDan Williams 		sci_unsolicited_frame_control_get_header(&ihost->uf_control,
1716d1c637c3SDan Williams 							      frame_index,
1717d1c637c3SDan Williams 							      &frame_header);
1718d1c637c3SDan Williams 
1719d1c637c3SDan Williams 		word_cnt = sizeof(struct ssp_frame_hdr) / sizeof(u32);
1720d1c637c3SDan Williams 		sci_swab32_cpy(&ssp_hdr, frame_header, word_cnt);
1721d1c637c3SDan Williams 
1722d1c637c3SDan Williams 		if (ssp_hdr.frame_type == SSP_RESPONSE) {
1723d1c637c3SDan Williams 			struct ssp_response_iu *resp_iu;
1724d1c637c3SDan Williams 			ssize_t word_cnt = SSP_RESP_IU_MAX_SIZE / sizeof(u32);
1725d1c637c3SDan Williams 
172689a7301fSDan Williams 			sci_unsolicited_frame_control_get_buffer(&ihost->uf_control,
1727d1c637c3SDan Williams 								      frame_index,
1728d1c637c3SDan Williams 								      (void **)&resp_iu);
1729d1c637c3SDan Williams 
17305076a1a9SDan Williams 			sci_swab32_cpy(&ireq->ssp.rsp, resp_iu, word_cnt);
1731d1c637c3SDan Williams 
17325076a1a9SDan Williams 			resp_iu = &ireq->ssp.rsp;
1733d1c637c3SDan Williams 
17341d6049a3SJohn Garry 			if (resp_iu->datapres == SAS_DATAPRES_RESPONSE_DATA ||
17351d6049a3SJohn Garry 			    resp_iu->datapres == SAS_DATAPRES_SENSE_DATA) {
173634a99158SDan Williams 				ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
173734a99158SDan Williams 				ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
173834a99158SDan Williams 			} else {
173934a99158SDan Williams 				ireq->scu_status = SCU_TASK_DONE_GOOD;
174034a99158SDan Williams 				ireq->sci_status = SCI_SUCCESS;
174134a99158SDan Williams 			}
1742d1c637c3SDan Williams 		} else {
1743d1c637c3SDan Williams 			/* not a response frame, why did it get forwarded? */
1744d9dcb4baSDan Williams 			dev_err(&ihost->pdev->dev,
1745d1c637c3SDan Williams 				"%s: SCIC IO Request 0x%p received unexpected "
17465076a1a9SDan Williams 				"frame %d type 0x%02x\n", __func__, ireq,
1747d1c637c3SDan Williams 				frame_index, ssp_hdr.frame_type);
1748d1c637c3SDan Williams 		}
1749d1c637c3SDan Williams 
1750d1c637c3SDan Williams 		/*
1751e301370aSEdmund Nadolski 		 * In any case we are done with this frame buffer return it to
1752e301370aSEdmund Nadolski 		 * the controller
1753d1c637c3SDan Williams 		 */
175489a7301fSDan Williams 		sci_controller_release_frame(ihost, frame_index);
1755d1c637c3SDan Williams 
1756d1c637c3SDan Williams 		return SCI_SUCCESS;
1757d1c637c3SDan Williams 	}
1758e301370aSEdmund Nadolski 
1759e301370aSEdmund Nadolski 	case SCI_REQ_TASK_WAIT_TC_RESP:
176089a7301fSDan Williams 		sci_io_request_copy_response(ireq);
17615076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
176289a7301fSDan Williams 		sci_controller_release_frame(ihost, frame_index);
1763d1c637c3SDan Williams 		return SCI_SUCCESS;
1764e301370aSEdmund Nadolski 
1765e301370aSEdmund Nadolski 	case SCI_REQ_SMP_WAIT_RESP: {
176654b5e3a4SDan Williams 		struct sas_task *task = isci_request_access_task(ireq);
176754b5e3a4SDan Williams 		struct scatterlist *sg = &task->smp_task.smp_resp;
176854b5e3a4SDan Williams 		void *frame_header, *kaddr;
176954b5e3a4SDan Williams 		u8 *rsp;
1770d1c637c3SDan Williams 
177189a7301fSDan Williams 		sci_unsolicited_frame_control_get_header(&ihost->uf_control,
1772d1c637c3SDan Williams 							 frame_index,
1773d1c637c3SDan Williams 							 &frame_header);
177477dfce07SCong Wang 		kaddr = kmap_atomic(sg_page(sg));
177554b5e3a4SDan Williams 		rsp = kaddr + sg->offset;
177654b5e3a4SDan Williams 		sci_swab32_cpy(rsp, frame_header, 1);
1777d1c637c3SDan Williams 
177854b5e3a4SDan Williams 		if (rsp[0] == SMP_RESPONSE) {
1779d1c637c3SDan Williams 			void *smp_resp;
1780d1c637c3SDan Williams 
178189a7301fSDan Williams 			sci_unsolicited_frame_control_get_buffer(&ihost->uf_control,
1782d1c637c3SDan Williams 								 frame_index,
1783d1c637c3SDan Williams 								 &smp_resp);
1784d1c637c3SDan Williams 
178554b5e3a4SDan Williams 			word_cnt = (sg->length/4)-1;
178654b5e3a4SDan Williams 			if (word_cnt > 0)
178754b5e3a4SDan Williams 				word_cnt = min_t(unsigned int, word_cnt,
178854b5e3a4SDan Williams 						 SCU_UNSOLICITED_FRAME_BUFFER_SIZE/4);
178954b5e3a4SDan Williams 			sci_swab32_cpy(rsp + 4, smp_resp, word_cnt);
1790d1c637c3SDan Williams 
179134a99158SDan Williams 			ireq->scu_status = SCU_TASK_DONE_GOOD;
179234a99158SDan Williams 			ireq->sci_status = SCI_SUCCESS;
17935076a1a9SDan Williams 			sci_change_state(&ireq->sm, SCI_REQ_SMP_WAIT_TC_COMP);
1794d1c637c3SDan Williams 		} else {
1795e301370aSEdmund Nadolski 			/*
1796e301370aSEdmund Nadolski 			 * This was not a response frame why did it get
1797e301370aSEdmund Nadolski 			 * forwarded?
1798e301370aSEdmund Nadolski 			 */
1799d9dcb4baSDan Williams 			dev_err(&ihost->pdev->dev,
1800e301370aSEdmund Nadolski 				"%s: SCIC SMP Request 0x%p received unexpected "
1801e301370aSEdmund Nadolski 				"frame %d type 0x%02x\n",
1802e301370aSEdmund Nadolski 				__func__,
18035076a1a9SDan Williams 				ireq,
1804e301370aSEdmund Nadolski 				frame_index,
180554b5e3a4SDan Williams 				rsp[0]);
1806d1c637c3SDan Williams 
180734a99158SDan Williams 			ireq->scu_status = SCU_TASK_DONE_SMP_FRM_TYPE_ERR;
180834a99158SDan Williams 			ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
18095076a1a9SDan Williams 			sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
1810d1c637c3SDan Williams 		}
181177dfce07SCong Wang 		kunmap_atomic(kaddr);
1812d1c637c3SDan Williams 
181389a7301fSDan Williams 		sci_controller_release_frame(ihost, frame_index);
1814d1c637c3SDan Williams 
1815d1c637c3SDan Williams 		return SCI_SUCCESS;
1816d1c637c3SDan Williams 	}
1817e301370aSEdmund Nadolski 
1818e301370aSEdmund Nadolski 	case SCI_REQ_STP_UDMA_WAIT_TC_COMP:
181989a7301fSDan Williams 		return sci_stp_request_udma_general_frame_handler(ireq,
1820e301370aSEdmund Nadolski 								       frame_index);
1821e301370aSEdmund Nadolski 
1822e301370aSEdmund Nadolski 	case SCI_REQ_STP_UDMA_WAIT_D2H:
1823d1c637c3SDan Williams 		/* Use the general frame handler to copy the resposne data */
182434a99158SDan Williams 		status = sci_stp_request_udma_general_frame_handler(ireq, frame_index);
1825d1c637c3SDan Williams 
1826d1c637c3SDan Williams 		if (status != SCI_SUCCESS)
1827d1c637c3SDan Williams 			return status;
1828d1c637c3SDan Williams 
182934a99158SDan Williams 		ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
183034a99158SDan Williams 		ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
183134a99158SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
1832d1c637c3SDan Williams 		return SCI_SUCCESS;
1833e301370aSEdmund Nadolski 
1834e301370aSEdmund Nadolski 	case SCI_REQ_STP_NON_DATA_WAIT_D2H: {
1835d1c637c3SDan Williams 		struct dev_to_host_fis *frame_header;
1836d1c637c3SDan Williams 		u32 *frame_buffer;
1837d1c637c3SDan Williams 
183889a7301fSDan Williams 		status = sci_unsolicited_frame_control_get_header(&ihost->uf_control,
1839d1c637c3SDan Williams 								       frame_index,
1840d1c637c3SDan Williams 								       (void **)&frame_header);
1841d1c637c3SDan Williams 
1842d1c637c3SDan Williams 		if (status != SCI_SUCCESS) {
1843d9dcb4baSDan Williams 			dev_err(&ihost->pdev->dev,
1844e301370aSEdmund Nadolski 				"%s: SCIC IO Request 0x%p could not get frame "
1845e301370aSEdmund Nadolski 				"header for frame index %d, status %x\n",
1846e301370aSEdmund Nadolski 				__func__,
1847e301370aSEdmund Nadolski 				stp_req,
1848e301370aSEdmund Nadolski 				frame_index,
1849e301370aSEdmund Nadolski 				status);
1850d1c637c3SDan Williams 
1851d1c637c3SDan Williams 			return status;
1852d1c637c3SDan Williams 		}
1853d1c637c3SDan Williams 
1854d1c637c3SDan Williams 		switch (frame_header->fis_type) {
1855d1c637c3SDan Williams 		case FIS_REGD2H:
185689a7301fSDan Williams 			sci_unsolicited_frame_control_get_buffer(&ihost->uf_control,
1857d1c637c3SDan Williams 								      frame_index,
1858d1c637c3SDan Williams 								      (void **)&frame_buffer);
1859d1c637c3SDan Williams 
186089a7301fSDan Williams 			sci_controller_copy_sata_response(&ireq->stp.rsp,
1861d1c637c3SDan Williams 							       frame_header,
1862d1c637c3SDan Williams 							       frame_buffer);
1863d1c637c3SDan Williams 
1864d1c637c3SDan Williams 			/* The command has completed with error */
186534a99158SDan Williams 			ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
186634a99158SDan Williams 			ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
1867d1c637c3SDan Williams 			break;
1868d1c637c3SDan Williams 
1869d1c637c3SDan Williams 		default:
1870d9dcb4baSDan Williams 			dev_warn(&ihost->pdev->dev,
1871d1c637c3SDan Williams 				 "%s: IO Request:0x%p Frame Id:%d protocol "
1872d1c637c3SDan Williams 				  "violation occurred\n", __func__, stp_req,
1873d1c637c3SDan Williams 				  frame_index);
1874d1c637c3SDan Williams 
187534a99158SDan Williams 			ireq->scu_status = SCU_TASK_DONE_UNEXP_FIS;
187634a99158SDan Williams 			ireq->sci_status = SCI_FAILURE_PROTOCOL_VIOLATION;
1877d1c637c3SDan Williams 			break;
1878d1c637c3SDan Williams 		}
1879d1c637c3SDan Williams 
18805076a1a9SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
1881d1c637c3SDan Williams 
1882d1c637c3SDan Williams 		/* Frame has been decoded return it to the controller */
188389a7301fSDan Williams 		sci_controller_release_frame(ihost, frame_index);
1884d1c637c3SDan Williams 
1885d1c637c3SDan Williams 		return status;
1886d1c637c3SDan Williams 	}
1887e301370aSEdmund Nadolski 
1888e301370aSEdmund Nadolski 	case SCI_REQ_STP_PIO_WAIT_FRAME: {
1889d1c637c3SDan Williams 		struct sas_task *task = isci_request_access_task(ireq);
1890d1c637c3SDan Williams 		struct dev_to_host_fis *frame_header;
1891d1c637c3SDan Williams 		u32 *frame_buffer;
1892d1c637c3SDan Williams 
189389a7301fSDan Williams 		status = sci_unsolicited_frame_control_get_header(&ihost->uf_control,
1894d1c637c3SDan Williams 								       frame_index,
1895d1c637c3SDan Williams 								       (void **)&frame_header);
1896d1c637c3SDan Williams 
1897d1c637c3SDan Williams 		if (status != SCI_SUCCESS) {
1898d9dcb4baSDan Williams 			dev_err(&ihost->pdev->dev,
1899e301370aSEdmund Nadolski 				"%s: SCIC IO Request 0x%p could not get frame "
1900e301370aSEdmund Nadolski 				"header for frame index %d, status %x\n",
1901d1c637c3SDan Williams 				__func__, stp_req, frame_index, status);
1902d1c637c3SDan Williams 			return status;
1903d1c637c3SDan Williams 		}
1904d1c637c3SDan Williams 
1905d1c637c3SDan Williams 		switch (frame_header->fis_type) {
1906d1c637c3SDan Williams 		case FIS_PIO_SETUP:
1907d1c637c3SDan Williams 			/* Get from the frame buffer the PIO Setup Data */
190889a7301fSDan Williams 			sci_unsolicited_frame_control_get_buffer(&ihost->uf_control,
1909d1c637c3SDan Williams 								      frame_index,
1910d1c637c3SDan Williams 								      (void **)&frame_buffer);
1911d1c637c3SDan Williams 
1912e301370aSEdmund Nadolski 			/* Get the data from the PIO Setup The SCU Hardware
1913e301370aSEdmund Nadolski 			 * returns first word in the frame_header and the rest
1914e301370aSEdmund Nadolski 			 * of the data is in the frame buffer so we need to
1915e301370aSEdmund Nadolski 			 * back up one dword
1916d1c637c3SDan Williams 			 */
1917d1c637c3SDan Williams 
1918d1c637c3SDan Williams 			/* transfer_count: first 16bits in the 4th dword */
1919ba7cb223SDan Williams 			stp_req->pio_len = frame_buffer[3] & 0xffff;
1920d1c637c3SDan Williams 
1921ba7cb223SDan Williams 			/* status: 4th byte in the 3rd dword */
1922ba7cb223SDan Williams 			stp_req->status = (frame_buffer[2] >> 24) & 0xff;
1923d1c637c3SDan Williams 
192489a7301fSDan Williams 			sci_controller_copy_sata_response(&ireq->stp.rsp,
1925d1c637c3SDan Williams 							       frame_header,
1926d1c637c3SDan Williams 							       frame_buffer);
1927d1c637c3SDan Williams 
19285076a1a9SDan Williams 			ireq->stp.rsp.status = stp_req->status;
1929d1c637c3SDan Williams 
1930d1c637c3SDan Williams 			/* The next state is dependent on whether the
1931d1c637c3SDan Williams 			 * request was PIO Data-in or Data out
1932d1c637c3SDan Williams 			 */
1933d1c637c3SDan Williams 			if (task->data_dir == DMA_FROM_DEVICE) {
19345076a1a9SDan Williams 				sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_DATA_IN);
1935d1c637c3SDan Williams 			} else if (task->data_dir == DMA_TO_DEVICE) {
1936d1c637c3SDan Williams 				/* Transmit data */
193789a7301fSDan Williams 				status = sci_stp_request_pio_data_out_transmit_data(ireq);
1938d1c637c3SDan Williams 				if (status != SCI_SUCCESS)
1939d1c637c3SDan Williams 					break;
19405076a1a9SDan Williams 				sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_DATA_OUT);
1941d1c637c3SDan Williams 			}
1942d1c637c3SDan Williams 			break;
1943e301370aSEdmund Nadolski 
1944d1c637c3SDan Williams 		case FIS_SETDEVBITS:
19455076a1a9SDan Williams 			sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_WAIT_FRAME);
1946d1c637c3SDan Williams 			break;
1947e301370aSEdmund Nadolski 
1948d1c637c3SDan Williams 		case FIS_REGD2H:
1949d1c637c3SDan Williams 			if (frame_header->status & ATA_BUSY) {
1950e301370aSEdmund Nadolski 				/*
1951e301370aSEdmund Nadolski 				 * Now why is the drive sending a D2H Register
1952e301370aSEdmund Nadolski 				 * FIS when it is still busy?  Do nothing since
1953e301370aSEdmund Nadolski 				 * we are still in the right state.
1954d1c637c3SDan Williams 				 */
1955d9dcb4baSDan Williams 				dev_dbg(&ihost->pdev->dev,
1956d1c637c3SDan Williams 					"%s: SCIC PIO Request 0x%p received "
1957d1c637c3SDan Williams 					"D2H Register FIS with BSY status "
1958e301370aSEdmund Nadolski 					"0x%x\n",
1959e301370aSEdmund Nadolski 					__func__,
1960e301370aSEdmund Nadolski 					stp_req,
1961d1c637c3SDan Williams 					frame_header->status);
1962d1c637c3SDan Williams 				break;
1963d1c637c3SDan Williams 			}
1964d1c637c3SDan Williams 
196589a7301fSDan Williams 			sci_unsolicited_frame_control_get_buffer(&ihost->uf_control,
1966d1c637c3SDan Williams 								      frame_index,
1967d1c637c3SDan Williams 								      (void **)&frame_buffer);
1968d1c637c3SDan Williams 
196949bd665cSMaciej Patelczyk 			sci_controller_copy_sata_response(&ireq->stp.rsp,
1970d1c637c3SDan Williams 							       frame_header,
1971d1c637c3SDan Williams 							       frame_buffer);
1972d1c637c3SDan Williams 
197334a99158SDan Williams 			ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
197434a99158SDan Williams 			ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
19755076a1a9SDan Williams 			sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
1976d1c637c3SDan Williams 			break;
1977e301370aSEdmund Nadolski 
1978d1c637c3SDan Williams 		default:
1979d1c637c3SDan Williams 			/* FIXME: what do we do here? */
1980d1c637c3SDan Williams 			break;
1981d1c637c3SDan Williams 		}
1982d1c637c3SDan Williams 
1983d1c637c3SDan Williams 		/* Frame is decoded return it to the controller */
198489a7301fSDan Williams 		sci_controller_release_frame(ihost, frame_index);
1985d1c637c3SDan Williams 
1986d1c637c3SDan Williams 		return status;
1987d1c637c3SDan Williams 	}
1988e301370aSEdmund Nadolski 
1989e301370aSEdmund Nadolski 	case SCI_REQ_STP_PIO_DATA_IN: {
1990d1c637c3SDan Williams 		struct dev_to_host_fis *frame_header;
1991d1c637c3SDan Williams 		struct sata_fis_data *frame_buffer;
1992d1c637c3SDan Williams 
199389a7301fSDan Williams 		status = sci_unsolicited_frame_control_get_header(&ihost->uf_control,
1994d1c637c3SDan Williams 								       frame_index,
1995d1c637c3SDan Williams 								       (void **)&frame_header);
1996d1c637c3SDan Williams 
1997d1c637c3SDan Williams 		if (status != SCI_SUCCESS) {
1998d9dcb4baSDan Williams 			dev_err(&ihost->pdev->dev,
1999e301370aSEdmund Nadolski 				"%s: SCIC IO Request 0x%p could not get frame "
2000e301370aSEdmund Nadolski 				"header for frame index %d, status %x\n",
2001e301370aSEdmund Nadolski 				__func__,
2002e301370aSEdmund Nadolski 				stp_req,
2003e301370aSEdmund Nadolski 				frame_index,
2004e301370aSEdmund Nadolski 				status);
2005d1c637c3SDan Williams 			return status;
2006d1c637c3SDan Williams 		}
2007d1c637c3SDan Williams 
2008d1c637c3SDan Williams 		if (frame_header->fis_type != FIS_DATA) {
2009d9dcb4baSDan Williams 			dev_err(&ihost->pdev->dev,
2010d1c637c3SDan Williams 				"%s: SCIC PIO Request 0x%p received frame %d "
2011d1c637c3SDan Williams 				"with fis type 0x%02x when expecting a data "
2012e301370aSEdmund Nadolski 				"fis.\n",
2013e301370aSEdmund Nadolski 				__func__,
2014e301370aSEdmund Nadolski 				stp_req,
2015e301370aSEdmund Nadolski 				frame_index,
2016d1c637c3SDan Williams 				frame_header->fis_type);
2017d1c637c3SDan Williams 
201834a99158SDan Williams 			ireq->scu_status = SCU_TASK_DONE_GOOD;
201934a99158SDan Williams 			ireq->sci_status = SCI_FAILURE_IO_REQUIRES_SCSI_ABORT;
20205076a1a9SDan Williams 			sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
2021d1c637c3SDan Williams 
2022d1c637c3SDan Williams 			/* Frame is decoded return it to the controller */
202389a7301fSDan Williams 			sci_controller_release_frame(ihost, frame_index);
2024d1c637c3SDan Williams 			return status;
2025d1c637c3SDan Williams 		}
2026d1c637c3SDan Williams 
2027ba7cb223SDan Williams 		if (stp_req->sgl.index < 0) {
20285076a1a9SDan Williams 			ireq->saved_rx_frame_index = frame_index;
2029ba7cb223SDan Williams 			stp_req->pio_len = 0;
2030d1c637c3SDan Williams 		} else {
203189a7301fSDan Williams 			sci_unsolicited_frame_control_get_buffer(&ihost->uf_control,
2032d1c637c3SDan Williams 								      frame_index,
2033d1c637c3SDan Williams 								      (void **)&frame_buffer);
2034d1c637c3SDan Williams 
203589a7301fSDan Williams 			status = sci_stp_request_pio_data_in_copy_data(stp_req,
2036d1c637c3SDan Williams 									    (u8 *)frame_buffer);
2037d1c637c3SDan Williams 
2038d1c637c3SDan Williams 			/* Frame is decoded return it to the controller */
203989a7301fSDan Williams 			sci_controller_release_frame(ihost, frame_index);
2040d1c637c3SDan Williams 		}
2041d1c637c3SDan Williams 
2042d1c637c3SDan Williams 		/* Check for the end of the transfer, are there more
2043d1c637c3SDan Williams 		 * bytes remaining for this data transfer
2044d1c637c3SDan Williams 		 */
2045ba7cb223SDan Williams 		if (status != SCI_SUCCESS || stp_req->pio_len != 0)
2046d1c637c3SDan Williams 			return status;
2047d1c637c3SDan Williams 
2048ba7cb223SDan Williams 		if ((stp_req->status & ATA_BUSY) == 0) {
204934a99158SDan Williams 			ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
205034a99158SDan Williams 			ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
20515076a1a9SDan Williams 			sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
2052d1c637c3SDan Williams 		} else {
20535076a1a9SDan Williams 			sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_WAIT_FRAME);
2054d1c637c3SDan Williams 		}
2055d1c637c3SDan Williams 		return status;
2056d1c637c3SDan Williams 	}
2057e301370aSEdmund Nadolski 
2058b50102d3SDan Williams 	case SCI_REQ_ATAPI_WAIT_PIO_SETUP: {
2059b50102d3SDan Williams 		struct sas_task *task = isci_request_access_task(ireq);
2060b50102d3SDan Williams 
2061b50102d3SDan Williams 		sci_controller_release_frame(ihost, frame_index);
2062b50102d3SDan Williams 		ireq->target_device->working_request = ireq;
2063b50102d3SDan Williams 		if (task->data_dir == DMA_NONE) {
2064b50102d3SDan Williams 			sci_change_state(&ireq->sm, SCI_REQ_ATAPI_WAIT_TC_COMP);
2065b50102d3SDan Williams 			scu_atapi_reconstruct_raw_frame_task_context(ireq);
2066b50102d3SDan Williams 		} else {
2067b50102d3SDan Williams 			sci_change_state(&ireq->sm, SCI_REQ_ATAPI_WAIT_D2H);
2068b50102d3SDan Williams 			scu_atapi_construct_task_context(ireq);
2069b50102d3SDan Williams 		}
2070b50102d3SDan Williams 
2071b50102d3SDan Williams 		sci_controller_continue_io(ireq);
2072b50102d3SDan Williams 		return SCI_SUCCESS;
2073b50102d3SDan Williams 	}
2074b50102d3SDan Williams 	case SCI_REQ_ATAPI_WAIT_D2H:
2075b50102d3SDan Williams 		return atapi_d2h_reg_frame_handler(ireq, frame_index);
2076e301370aSEdmund Nadolski 	case SCI_REQ_ABORTING:
2077e301370aSEdmund Nadolski 		/*
2078e301370aSEdmund Nadolski 		 * TODO: Is it even possible to get an unsolicited frame in the
2079d1c637c3SDan Williams 		 * aborting state?
2080d1c637c3SDan Williams 		 */
208189a7301fSDan Williams 		sci_controller_release_frame(ihost, frame_index);
2082d1c637c3SDan Williams 		return SCI_SUCCESS;
2083e301370aSEdmund Nadolski 
2084d1c637c3SDan Williams 	default:
2085d9dcb4baSDan Williams 		dev_warn(&ihost->pdev->dev,
2086e301370aSEdmund Nadolski 			 "%s: SCIC IO Request given unexpected frame %x while "
2087e301370aSEdmund Nadolski 			 "in state %d\n",
2088e301370aSEdmund Nadolski 			 __func__,
2089e301370aSEdmund Nadolski 			 frame_index,
2090e301370aSEdmund Nadolski 			 state);
2091d1c637c3SDan Williams 
209289a7301fSDan Williams 		sci_controller_release_frame(ihost, frame_index);
2093d1c637c3SDan Williams 		return SCI_FAILURE_INVALID_STATE;
2094d1c637c3SDan Williams 	}
2095d1c637c3SDan Williams }
2096d1c637c3SDan Williams 
stp_request_udma_await_tc_event(struct isci_request * ireq,u32 completion_code)20975076a1a9SDan Williams static enum sci_status stp_request_udma_await_tc_event(struct isci_request *ireq,
20985dec6f4eSDan Williams 						       u32 completion_code)
20995dec6f4eSDan Williams {
21005dec6f4eSDan Williams 	switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
21015dec6f4eSDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
210234a99158SDan Williams 		ireq->scu_status = SCU_TASK_DONE_GOOD;
210334a99158SDan Williams 		ireq->sci_status = SCI_SUCCESS;
210434a99158SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
21055dec6f4eSDan Williams 		break;
21065dec6f4eSDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_FIS):
21075dec6f4eSDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR):
2108a7e255a3SDan Williams 		/* We must check ther response buffer to see if the D2H
2109a7e255a3SDan Williams 		 * Register FIS was received before we got the TC
2110a7e255a3SDan Williams 		 * completion.
2111a7e255a3SDan Williams 		 */
21125076a1a9SDan Williams 		if (ireq->stp.rsp.fis_type == FIS_REGD2H) {
211387805162SJeff Skirvin 			sci_remote_device_suspend(ireq->target_device,
211487805162SJeff Skirvin 						  SCI_SW_SUSPEND_NORMAL);
211587805162SJeff Skirvin 
211634a99158SDan Williams 			ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
211734a99158SDan Williams 			ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
211834a99158SDan Williams 			sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
21195dec6f4eSDan Williams 		} else {
2120a7e255a3SDan Williams 			/* If we have an error completion status for the
2121a7e255a3SDan Williams 			 * TC then we can expect a D2H register FIS from
2122a7e255a3SDan Williams 			 * the device so we must change state to wait
2123a7e255a3SDan Williams 			 * for it
2124a7e255a3SDan Williams 			 */
21255076a1a9SDan Williams 			sci_change_state(&ireq->sm, SCI_REQ_STP_UDMA_WAIT_D2H);
21265dec6f4eSDan Williams 		}
21275dec6f4eSDan Williams 		break;
21285dec6f4eSDan Williams 
2129a7e255a3SDan Williams 	/* TODO Check to see if any of these completion status need to
2130a7e255a3SDan Williams 	 * wait for the device to host register fis.
2131a7e255a3SDan Williams 	 */
2132a7e255a3SDan Williams 	/* TODO We can retry the command for SCU_TASK_DONE_CMD_LL_R_ERR
2133a7e255a3SDan Williams 	 * - this comes only for B0
2134a7e255a3SDan Williams 	 */
21355dec6f4eSDan Williams 	default:
21365dec6f4eSDan Williams 		/* All other completion status cause the IO to be complete. */
213734a99158SDan Williams 		ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
213834a99158SDan Williams 		ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
213934a99158SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
21405dec6f4eSDan Williams 		break;
21415dec6f4eSDan Williams 	}
21425dec6f4eSDan Williams 
2143dc0bfdb5SYANG LI 	return SCI_SUCCESS;
21445dec6f4eSDan Williams }
21455dec6f4eSDan Williams 
atapi_raw_completion(struct isci_request * ireq,u32 completion_code,enum sci_base_request_states next)2146b50102d3SDan Williams static enum sci_status atapi_raw_completion(struct isci_request *ireq, u32 completion_code,
2147b50102d3SDan Williams 						  enum sci_base_request_states next)
2148b50102d3SDan Williams {
2149b50102d3SDan Williams 	switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
2150b50102d3SDan Williams 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
2151b50102d3SDan Williams 		ireq->scu_status = SCU_TASK_DONE_GOOD;
2152b50102d3SDan Williams 		ireq->sci_status = SCI_SUCCESS;
2153b50102d3SDan Williams 		sci_change_state(&ireq->sm, next);
2154b50102d3SDan Williams 		break;
2155b50102d3SDan Williams 	default:
2156b50102d3SDan Williams 		/* All other completion status cause the IO to be complete.
2157b50102d3SDan Williams 		 * If a NAK was received, then it is up to the user to retry
2158b50102d3SDan Williams 		 * the request.
2159b50102d3SDan Williams 		 */
2160b50102d3SDan Williams 		ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
2161b50102d3SDan Williams 		ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
2162b50102d3SDan Williams 
2163b50102d3SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
2164b50102d3SDan Williams 		break;
2165b50102d3SDan Williams 	}
2166b50102d3SDan Williams 
216770ae13abSYang Li 	return SCI_SUCCESS;
2168b50102d3SDan Williams }
2169b50102d3SDan Williams 
atapi_data_tc_completion_handler(struct isci_request * ireq,u32 completion_code)2170b50102d3SDan Williams static enum sci_status atapi_data_tc_completion_handler(struct isci_request *ireq,
2171b50102d3SDan Williams 							u32 completion_code)
2172b50102d3SDan Williams {
2173b50102d3SDan Williams 	struct isci_remote_device *idev = ireq->target_device;
2174b50102d3SDan Williams 	struct dev_to_host_fis *d2h = &ireq->stp.rsp;
2175b50102d3SDan Williams 	enum sci_status status = SCI_SUCCESS;
2176b50102d3SDan Williams 
2177b50102d3SDan Williams 	switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
2178b50102d3SDan Williams 	case (SCU_TASK_DONE_GOOD << SCU_COMPLETION_TL_STATUS_SHIFT):
2179b50102d3SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
2180b50102d3SDan Williams 		break;
2181b50102d3SDan Williams 
2182b50102d3SDan Williams 	case (SCU_TASK_DONE_UNEXP_FIS << SCU_COMPLETION_TL_STATUS_SHIFT): {
2183b50102d3SDan Williams 		u16 len = sci_req_tx_bytes(ireq);
2184b50102d3SDan Williams 
2185823ae99eSJulia Lawall 		/* likely non-error data underrun, workaround missing
2186b50102d3SDan Williams 		 * d2h frame from the controller
2187b50102d3SDan Williams 		 */
2188b50102d3SDan Williams 		if (d2h->fis_type != FIS_REGD2H) {
2189b50102d3SDan Williams 			d2h->fis_type = FIS_REGD2H;
2190b50102d3SDan Williams 			d2h->flags = (1 << 6);
2191b50102d3SDan Williams 			d2h->status = 0x50;
2192b50102d3SDan Williams 			d2h->error = 0;
2193b50102d3SDan Williams 			d2h->lbal = 0;
2194b50102d3SDan Williams 			d2h->byte_count_low = len & 0xff;
2195b50102d3SDan Williams 			d2h->byte_count_high = len >> 8;
2196b50102d3SDan Williams 			d2h->device = 0xa0;
2197b50102d3SDan Williams 			d2h->lbal_exp = 0;
2198b50102d3SDan Williams 			d2h->lbam_exp = 0;
2199b50102d3SDan Williams 			d2h->lbah_exp = 0;
2200b50102d3SDan Williams 			d2h->_r_a = 0;
2201b50102d3SDan Williams 			d2h->sector_count = 0x3;
2202b50102d3SDan Williams 			d2h->sector_count_exp = 0;
2203b50102d3SDan Williams 			d2h->_r_b = 0;
2204b50102d3SDan Williams 			d2h->_r_c = 0;
2205b50102d3SDan Williams 			d2h->_r_d = 0;
2206b50102d3SDan Williams 		}
2207b50102d3SDan Williams 
2208b50102d3SDan Williams 		ireq->scu_status = SCU_TASK_DONE_GOOD;
2209b50102d3SDan Williams 		ireq->sci_status = SCI_SUCCESS_IO_DONE_EARLY;
2210b50102d3SDan Williams 		status = ireq->sci_status;
2211b50102d3SDan Williams 
2212b50102d3SDan Williams 		/* the hw will have suspended the rnc, so complete the
2213b50102d3SDan Williams 		 * request upon pending resume
2214b50102d3SDan Williams 		 */
2215b50102d3SDan Williams 		sci_change_state(&idev->sm, SCI_STP_DEV_ATAPI_ERROR);
2216b50102d3SDan Williams 		break;
2217b50102d3SDan Williams 	}
2218b50102d3SDan Williams 	case (SCU_TASK_DONE_EXCESS_DATA << SCU_COMPLETION_TL_STATUS_SHIFT):
2219b50102d3SDan Williams 		/* In this case, there is no UF coming after.
2220b50102d3SDan Williams 		 * compelte the IO now.
2221b50102d3SDan Williams 		 */
2222b50102d3SDan Williams 		ireq->scu_status = SCU_TASK_DONE_GOOD;
2223b50102d3SDan Williams 		ireq->sci_status = SCI_SUCCESS;
2224b50102d3SDan Williams 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
2225b50102d3SDan Williams 		break;
2226b50102d3SDan Williams 
2227b50102d3SDan Williams 	default:
2228b50102d3SDan Williams 		if (d2h->fis_type == FIS_REGD2H) {
2229b50102d3SDan Williams 			/* UF received change the device state to ATAPI_ERROR */
2230b50102d3SDan Williams 			status = ireq->sci_status;
2231b50102d3SDan Williams 			sci_change_state(&idev->sm, SCI_STP_DEV_ATAPI_ERROR);
2232b50102d3SDan Williams 		} else {
22334907cb7bSAnatol Pomozov 			/* If receiving any non-success TC status, no UF
2234b50102d3SDan Williams 			 * received yet, then an UF for the status fis
2235b50102d3SDan Williams 			 * is coming after (XXX: suspect this is
2236b50102d3SDan Williams 			 * actually a protocol error or a bug like the
2237b50102d3SDan Williams 			 * DONE_UNEXP_FIS case)
2238b50102d3SDan Williams 			 */
2239b50102d3SDan Williams 			ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
2240b50102d3SDan Williams 			ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
2241b50102d3SDan Williams 
2242b50102d3SDan Williams 			sci_change_state(&ireq->sm, SCI_REQ_ATAPI_WAIT_D2H);
2243b50102d3SDan Williams 		}
2244b50102d3SDan Williams 		break;
2245b50102d3SDan Williams 	}
2246b50102d3SDan Williams 
2247b50102d3SDan Williams 	return status;
2248b50102d3SDan Williams }
2249b50102d3SDan Williams 
sci_request_smp_completion_status_is_tx_suspend(unsigned int completion_status)2250ac78ed0fSJeff Skirvin static int sci_request_smp_completion_status_is_tx_suspend(
2251ac78ed0fSJeff Skirvin 	unsigned int completion_status)
2252ac78ed0fSJeff Skirvin {
2253ac78ed0fSJeff Skirvin 	switch (completion_status) {
2254ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION:
2255ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
2256ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
2257ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
2258ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
2259ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
2260ac78ed0fSJeff Skirvin 		return 1;
2261ac78ed0fSJeff Skirvin 	}
2262ac78ed0fSJeff Skirvin 	return 0;
2263ac78ed0fSJeff Skirvin }
2264ac78ed0fSJeff Skirvin 
sci_request_smp_completion_status_is_tx_rx_suspend(unsigned int completion_status)2265ac78ed0fSJeff Skirvin static int sci_request_smp_completion_status_is_tx_rx_suspend(
2266ac78ed0fSJeff Skirvin 	unsigned int completion_status)
2267ac78ed0fSJeff Skirvin {
2268ac78ed0fSJeff Skirvin 	return 0; /* There are no Tx/Rx SMP suspend conditions. */
2269ac78ed0fSJeff Skirvin }
2270ac78ed0fSJeff Skirvin 
sci_request_ssp_completion_status_is_tx_suspend(unsigned int completion_status)2271ac78ed0fSJeff Skirvin static int sci_request_ssp_completion_status_is_tx_suspend(
2272ac78ed0fSJeff Skirvin 	unsigned int completion_status)
2273ac78ed0fSJeff Skirvin {
2274ac78ed0fSJeff Skirvin 	switch (completion_status) {
2275ac78ed0fSJeff Skirvin 	case SCU_TASK_DONE_TX_RAW_CMD_ERR:
2276ac78ed0fSJeff Skirvin 	case SCU_TASK_DONE_LF_ERR:
2277ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION:
2278ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
2279ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
2280ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
2281ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
2282ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
2283ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY:
2284ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED:
2285ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED:
2286ac78ed0fSJeff Skirvin 		return 1;
2287ac78ed0fSJeff Skirvin 	}
2288ac78ed0fSJeff Skirvin 	return 0;
2289ac78ed0fSJeff Skirvin }
2290ac78ed0fSJeff Skirvin 
sci_request_ssp_completion_status_is_tx_rx_suspend(unsigned int completion_status)2291ac78ed0fSJeff Skirvin static int sci_request_ssp_completion_status_is_tx_rx_suspend(
2292ac78ed0fSJeff Skirvin 	unsigned int completion_status)
2293ac78ed0fSJeff Skirvin {
2294ac78ed0fSJeff Skirvin 	return 0; /* There are no Tx/Rx SSP suspend conditions. */
2295ac78ed0fSJeff Skirvin }
2296ac78ed0fSJeff Skirvin 
sci_request_stpsata_completion_status_is_tx_suspend(unsigned int completion_status)2297ac78ed0fSJeff Skirvin static int sci_request_stpsata_completion_status_is_tx_suspend(
2298ac78ed0fSJeff Skirvin 	unsigned int completion_status)
2299ac78ed0fSJeff Skirvin {
2300ac78ed0fSJeff Skirvin 	switch (completion_status) {
2301ac78ed0fSJeff Skirvin 	case SCU_TASK_DONE_TX_RAW_CMD_ERR:
2302ac78ed0fSJeff Skirvin 	case SCU_TASK_DONE_LL_R_ERR:
2303ac78ed0fSJeff Skirvin 	case SCU_TASK_DONE_LL_PERR:
2304ac78ed0fSJeff Skirvin 	case SCU_TASK_DONE_REG_ERR:
2305ac78ed0fSJeff Skirvin 	case SCU_TASK_DONE_SDB_ERR:
2306ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION:
2307ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
2308ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
2309ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
2310ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
2311ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
2312ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY:
2313ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED:
2314ac78ed0fSJeff Skirvin 	case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED:
2315ac78ed0fSJeff Skirvin 		return 1;
2316ac78ed0fSJeff Skirvin 	}
2317ac78ed0fSJeff Skirvin 	return 0;
2318ac78ed0fSJeff Skirvin }
2319ac78ed0fSJeff Skirvin 
2320ac78ed0fSJeff Skirvin 
sci_request_stpsata_completion_status_is_tx_rx_suspend(unsigned int completion_status)2321ac78ed0fSJeff Skirvin static int sci_request_stpsata_completion_status_is_tx_rx_suspend(
2322ac78ed0fSJeff Skirvin 	unsigned int completion_status)
2323ac78ed0fSJeff Skirvin {
2324ac78ed0fSJeff Skirvin 	switch (completion_status) {
2325ac78ed0fSJeff Skirvin 	case SCU_TASK_DONE_LF_ERR:
2326ac78ed0fSJeff Skirvin 	case SCU_TASK_DONE_LL_SY_TERM:
2327ac78ed0fSJeff Skirvin 	case SCU_TASK_DONE_LL_LF_TERM:
2328ac78ed0fSJeff Skirvin 	case SCU_TASK_DONE_BREAK_RCVD:
2329ac78ed0fSJeff Skirvin 	case SCU_TASK_DONE_INV_FIS_LEN:
2330ac78ed0fSJeff Skirvin 	case SCU_TASK_DONE_UNEXP_FIS:
2331ac78ed0fSJeff Skirvin 	case SCU_TASK_DONE_UNEXP_SDBFIS:
2332ac78ed0fSJeff Skirvin 	case SCU_TASK_DONE_MAX_PLD_ERR:
2333ac78ed0fSJeff Skirvin 		return 1;
2334ac78ed0fSJeff Skirvin 	}
2335ac78ed0fSJeff Skirvin 	return 0;
2336ac78ed0fSJeff Skirvin }
2337ac78ed0fSJeff Skirvin 
sci_request_handle_suspending_completions(struct isci_request * ireq,u32 completion_code)2338ac78ed0fSJeff Skirvin static void sci_request_handle_suspending_completions(
2339ac78ed0fSJeff Skirvin 	struct isci_request *ireq,
2340ac78ed0fSJeff Skirvin 	u32 completion_code)
2341ac78ed0fSJeff Skirvin {
2342ac78ed0fSJeff Skirvin 	int is_tx = 0;
2343ac78ed0fSJeff Skirvin 	int is_tx_rx = 0;
2344ac78ed0fSJeff Skirvin 
2345ac78ed0fSJeff Skirvin 	switch (ireq->protocol) {
2346ac78ed0fSJeff Skirvin 	case SAS_PROTOCOL_SMP:
2347ac78ed0fSJeff Skirvin 		is_tx = sci_request_smp_completion_status_is_tx_suspend(
2348ac78ed0fSJeff Skirvin 			completion_code);
2349ac78ed0fSJeff Skirvin 		is_tx_rx = sci_request_smp_completion_status_is_tx_rx_suspend(
2350ac78ed0fSJeff Skirvin 			completion_code);
2351ac78ed0fSJeff Skirvin 		break;
2352ac78ed0fSJeff Skirvin 	case SAS_PROTOCOL_SSP:
2353ac78ed0fSJeff Skirvin 		is_tx = sci_request_ssp_completion_status_is_tx_suspend(
2354ac78ed0fSJeff Skirvin 			completion_code);
2355ac78ed0fSJeff Skirvin 		is_tx_rx = sci_request_ssp_completion_status_is_tx_rx_suspend(
2356ac78ed0fSJeff Skirvin 			completion_code);
2357ac78ed0fSJeff Skirvin 		break;
2358ac78ed0fSJeff Skirvin 	case SAS_PROTOCOL_STP:
2359ac78ed0fSJeff Skirvin 		is_tx = sci_request_stpsata_completion_status_is_tx_suspend(
2360ac78ed0fSJeff Skirvin 			completion_code);
2361ac78ed0fSJeff Skirvin 		is_tx_rx =
2362ac78ed0fSJeff Skirvin 			sci_request_stpsata_completion_status_is_tx_rx_suspend(
2363ac78ed0fSJeff Skirvin 				completion_code);
2364ac78ed0fSJeff Skirvin 		break;
2365ac78ed0fSJeff Skirvin 	default:
2366ac78ed0fSJeff Skirvin 		dev_warn(&ireq->isci_host->pdev->dev,
2367ac78ed0fSJeff Skirvin 			 "%s: request %p has no valid protocol\n",
2368ac78ed0fSJeff Skirvin 			 __func__, ireq);
2369ac78ed0fSJeff Skirvin 		break;
2370ac78ed0fSJeff Skirvin 	}
2371ac78ed0fSJeff Skirvin 	if (is_tx || is_tx_rx) {
2372ac78ed0fSJeff Skirvin 		BUG_ON(is_tx && is_tx_rx);
2373ac78ed0fSJeff Skirvin 
2374ac78ed0fSJeff Skirvin 		sci_remote_node_context_suspend(
2375ac78ed0fSJeff Skirvin 			&ireq->target_device->rnc,
2376c94fc1adSJeff Skirvin 			SCI_HW_SUSPEND,
2377ac78ed0fSJeff Skirvin 			(is_tx_rx) ? SCU_EVENT_TL_RNC_SUSPEND_TX_RX
2378447bfbceSJeff Skirvin 				   : SCU_EVENT_TL_RNC_SUSPEND_TX);
2379ac78ed0fSJeff Skirvin 	}
2380ac78ed0fSJeff Skirvin }
2381ac78ed0fSJeff Skirvin 
2382a7e255a3SDan Williams enum sci_status
sci_io_request_tc_completion(struct isci_request * ireq,u32 completion_code)238389a7301fSDan Williams sci_io_request_tc_completion(struct isci_request *ireq,
2384e301370aSEdmund Nadolski 			     u32 completion_code)
2385a7e255a3SDan Williams {
2386a7e255a3SDan Williams 	enum sci_base_request_states state;
2387d9dcb4baSDan Williams 	struct isci_host *ihost = ireq->owning_controller;
2388a7e255a3SDan Williams 
23895076a1a9SDan Williams 	state = ireq->sm.current_state_id;
2390a7e255a3SDan Williams 
2391ac78ed0fSJeff Skirvin 	/* Decode those completions that signal upcoming suspension events. */
2392ac78ed0fSJeff Skirvin 	sci_request_handle_suspending_completions(
2393ac78ed0fSJeff Skirvin 		ireq, SCU_GET_COMPLETION_TL_STATUS(completion_code));
2394ac78ed0fSJeff Skirvin 
2395a7e255a3SDan Williams 	switch (state) {
2396e301370aSEdmund Nadolski 	case SCI_REQ_STARTED:
23975076a1a9SDan Williams 		return request_started_state_tc_event(ireq, completion_code);
2398e301370aSEdmund Nadolski 
2399e301370aSEdmund Nadolski 	case SCI_REQ_TASK_WAIT_TC_COMP:
24005076a1a9SDan Williams 		return ssp_task_request_await_tc_event(ireq,
2401e301370aSEdmund Nadolski 						       completion_code);
2402e301370aSEdmund Nadolski 
2403e301370aSEdmund Nadolski 	case SCI_REQ_SMP_WAIT_RESP:
24045076a1a9SDan Williams 		return smp_request_await_response_tc_event(ireq,
2405e301370aSEdmund Nadolski 							   completion_code);
2406e301370aSEdmund Nadolski 
2407e301370aSEdmund Nadolski 	case SCI_REQ_SMP_WAIT_TC_COMP:
24085076a1a9SDan Williams 		return smp_request_await_tc_event(ireq, completion_code);
2409e301370aSEdmund Nadolski 
2410e301370aSEdmund Nadolski 	case SCI_REQ_STP_UDMA_WAIT_TC_COMP:
24115076a1a9SDan Williams 		return stp_request_udma_await_tc_event(ireq,
2412e301370aSEdmund Nadolski 						       completion_code);
2413e301370aSEdmund Nadolski 
2414e301370aSEdmund Nadolski 	case SCI_REQ_STP_NON_DATA_WAIT_H2D:
24155076a1a9SDan Williams 		return stp_request_non_data_await_h2d_tc_event(ireq,
2416e301370aSEdmund Nadolski 							       completion_code);
2417e301370aSEdmund Nadolski 
2418e301370aSEdmund Nadolski 	case SCI_REQ_STP_PIO_WAIT_H2D:
24195076a1a9SDan Williams 		return stp_request_pio_await_h2d_completion_tc_event(ireq,
2420e301370aSEdmund Nadolski 								     completion_code);
2421e301370aSEdmund Nadolski 
2422e301370aSEdmund Nadolski 	case SCI_REQ_STP_PIO_DATA_OUT:
24235076a1a9SDan Williams 		return pio_data_out_tx_done_tc_event(ireq, completion_code);
2424e301370aSEdmund Nadolski 
2425e301370aSEdmund Nadolski 	case SCI_REQ_ABORTING:
24265076a1a9SDan Williams 		return request_aborting_state_tc_event(ireq,
2427e301370aSEdmund Nadolski 						       completion_code);
2428e301370aSEdmund Nadolski 
2429b50102d3SDan Williams 	case SCI_REQ_ATAPI_WAIT_H2D:
2430b50102d3SDan Williams 		return atapi_raw_completion(ireq, completion_code,
2431b50102d3SDan Williams 					    SCI_REQ_ATAPI_WAIT_PIO_SETUP);
2432b50102d3SDan Williams 
2433b50102d3SDan Williams 	case SCI_REQ_ATAPI_WAIT_TC_COMP:
2434b50102d3SDan Williams 		return atapi_raw_completion(ireq, completion_code,
2435b50102d3SDan Williams 					    SCI_REQ_ATAPI_WAIT_D2H);
2436b50102d3SDan Williams 
2437b50102d3SDan Williams 	case SCI_REQ_ATAPI_WAIT_D2H:
2438b50102d3SDan Williams 		return atapi_data_tc_completion_handler(ireq, completion_code);
2439b50102d3SDan Williams 
2440a7e255a3SDan Williams 	default:
2441d7a0ccddSDan Williams 		dev_warn(&ihost->pdev->dev, "%s: %x in wrong state %s\n",
2442d7a0ccddSDan Williams 			 __func__, completion_code, req_state_name(state));
2443a7e255a3SDan Williams 		return SCI_FAILURE_INVALID_STATE;
2444a7e255a3SDan Williams 	}
2445a7e255a3SDan Williams }
2446a7e255a3SDan Williams 
24476f231ddaSDan Williams /**
24486f231ddaSDan Williams  * isci_request_process_response_iu() - This function sets the status and
24496f231ddaSDan Williams  *    response iu, in the task struct, from the request object for the upper
24506f231ddaSDan Williams  *    layer driver.
2451db35a083SLee Jones  * @task: This parameter is the task struct from the upper layer driver.
24526f231ddaSDan Williams  * @resp_iu: This parameter points to the response iu of the completed request.
24536f231ddaSDan Williams  * @dev: This parameter specifies the linux device struct.
24546f231ddaSDan Williams  *
24556f231ddaSDan Williams  * none.
24566f231ddaSDan Williams  */
isci_request_process_response_iu(struct sas_task * task,struct ssp_response_iu * resp_iu,struct device * dev)24576f231ddaSDan Williams static void isci_request_process_response_iu(
24586f231ddaSDan Williams 	struct sas_task *task,
24596f231ddaSDan Williams 	struct ssp_response_iu *resp_iu,
24606f231ddaSDan Williams 	struct device *dev)
24616f231ddaSDan Williams {
24626f231ddaSDan Williams 	dev_dbg(dev,
24636f231ddaSDan Williams 		"%s: resp_iu = %p "
24646f231ddaSDan Williams 		"resp_iu->status = 0x%x,\nresp_iu->datapres = %d "
24656f231ddaSDan Williams 		"resp_iu->response_data_len = %x, "
246663eb7b6bSColin Ian King 		"resp_iu->sense_data_len = %x\nresponse data: ",
24676f231ddaSDan Williams 		__func__,
24686f231ddaSDan Williams 		resp_iu,
24696f231ddaSDan Williams 		resp_iu->status,
24706f231ddaSDan Williams 		resp_iu->datapres,
24716f231ddaSDan Williams 		resp_iu->response_data_len,
24726f231ddaSDan Williams 		resp_iu->sense_data_len);
24736f231ddaSDan Williams 
24746f231ddaSDan Williams 	task->task_status.stat = resp_iu->status;
24756f231ddaSDan Williams 
24766f231ddaSDan Williams 	/* libsas updates the task status fields based on the response iu. */
24776f231ddaSDan Williams 	sas_ssp_task_response(dev, task, resp_iu);
24786f231ddaSDan Williams }
24796f231ddaSDan Williams 
24806f231ddaSDan Williams /**
24816f231ddaSDan Williams  * isci_request_set_open_reject_status() - This function prepares the I/O
24826f231ddaSDan Williams  *    completion for OPEN_REJECT conditions.
24836f231ddaSDan Williams  * @request: This parameter is the completed isci_request object.
2484db35a083SLee Jones  * @task: This parameter is the task struct from the upper layer driver.
24856f231ddaSDan Williams  * @response_ptr: This parameter specifies the service response for the I/O.
24866f231ddaSDan Williams  * @status_ptr: This parameter specifies the exec status for the I/O.
24876f231ddaSDan Williams  * @open_rej_reason: This parameter specifies the encoded reason for the
24886f231ddaSDan Williams  *    abandon-class reject.
24896f231ddaSDan Williams  *
24906f231ddaSDan Williams  * none.
24916f231ddaSDan Williams  */
isci_request_set_open_reject_status(struct isci_request * request,struct sas_task * task,enum service_response * response_ptr,enum exec_status * status_ptr,enum sas_open_rej_reason open_rej_reason)24926f231ddaSDan Williams static void isci_request_set_open_reject_status(
24936f231ddaSDan Williams 	struct isci_request *request,
24946f231ddaSDan Williams 	struct sas_task *task,
24956f231ddaSDan Williams 	enum service_response *response_ptr,
24966f231ddaSDan Williams 	enum exec_status *status_ptr,
24976f231ddaSDan Williams 	enum sas_open_rej_reason open_rej_reason)
24986f231ddaSDan Williams {
24996f231ddaSDan Williams 	/* Task in the target is done. */
250038d8879bSDan Williams 	set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
25016f231ddaSDan Williams 	*response_ptr                     = SAS_TASK_UNDELIVERED;
25026f231ddaSDan Williams 	*status_ptr                       = SAS_OPEN_REJECT;
25036f231ddaSDan Williams 	task->task_status.open_rej_reason = open_rej_reason;
25046f231ddaSDan Williams }
25056f231ddaSDan Williams 
25066f231ddaSDan Williams /**
25076f231ddaSDan Williams  * isci_request_handle_controller_specific_errors() - This function decodes
25086f231ddaSDan Williams  *    controller-specific I/O completion error conditions.
2509db35a083SLee Jones  * @idev: Remote device
25106f231ddaSDan Williams  * @request: This parameter is the completed isci_request object.
2511db35a083SLee Jones  * @task: This parameter is the task struct from the upper layer driver.
25126f231ddaSDan Williams  * @response_ptr: This parameter specifies the service response for the I/O.
25136f231ddaSDan Williams  * @status_ptr: This parameter specifies the exec status for the I/O.
25146f231ddaSDan Williams  *
25156f231ddaSDan Williams  * none.
25166f231ddaSDan Williams  */
isci_request_handle_controller_specific_errors(struct isci_remote_device * idev,struct isci_request * request,struct sas_task * task,enum service_response * response_ptr,enum exec_status * status_ptr)25176f231ddaSDan Williams static void isci_request_handle_controller_specific_errors(
2518209fae14SDan Williams 	struct isci_remote_device *idev,
25196f231ddaSDan Williams 	struct isci_request *request,
25206f231ddaSDan Williams 	struct sas_task *task,
25216f231ddaSDan Williams 	enum service_response *response_ptr,
252214aaa9f0SJeff Skirvin 	enum exec_status *status_ptr)
25236f231ddaSDan Williams {
25246f231ddaSDan Williams 	unsigned int cstatus;
25256f231ddaSDan Williams 
25265076a1a9SDan Williams 	cstatus = request->scu_status;
25276f231ddaSDan Williams 
25286f231ddaSDan Williams 	dev_dbg(&request->isci_host->pdev->dev,
25296f231ddaSDan Williams 		"%s: %p SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR "
25306f231ddaSDan Williams 		"- controller status = 0x%x\n",
25316f231ddaSDan Williams 		__func__, request, cstatus);
25326f231ddaSDan Williams 
25336f231ddaSDan Williams 	/* Decode the controller-specific errors; most
25346f231ddaSDan Williams 	 * important is to recognize those conditions in which
25356f231ddaSDan Williams 	 * the target may still have a task outstanding that
25366f231ddaSDan Williams 	 * must be aborted.
25376f231ddaSDan Williams 	 *
25386f231ddaSDan Williams 	 * Note that there are SCU completion codes being
25396f231ddaSDan Williams 	 * named in the decode below for which SCIC has already
25406f231ddaSDan Williams 	 * done work to handle them in a way other than as
25416f231ddaSDan Williams 	 * a controller-specific completion code; these are left
25426f231ddaSDan Williams 	 * in the decode below for completeness sake.
25436f231ddaSDan Williams 	 */
25446f231ddaSDan Williams 	switch (cstatus) {
25456f231ddaSDan Williams 	case SCU_TASK_DONE_DMASETUP_DIRERR:
25466f231ddaSDan Williams 	/* Also SCU_TASK_DONE_SMP_FRM_TYPE_ERR: */
25476f231ddaSDan Williams 	case SCU_TASK_DONE_XFERCNT_ERR:
25486f231ddaSDan Williams 		/* Also SCU_TASK_DONE_SMP_UFI_ERR: */
25496f231ddaSDan Williams 		if (task->task_proto == SAS_PROTOCOL_SMP) {
25506f231ddaSDan Williams 			/* SCU_TASK_DONE_SMP_UFI_ERR == Task Done. */
25516f231ddaSDan Williams 			*response_ptr = SAS_TASK_COMPLETE;
25526f231ddaSDan Williams 
25536f231ddaSDan Williams 			/* See if the device has been/is being stopped. Note
25546f231ddaSDan Williams 			 * that we ignore the quiesce state, since we are
25556f231ddaSDan Williams 			 * concerned about the actual device state.
25566f231ddaSDan Williams 			 */
2557209fae14SDan Williams 			if (!idev)
25586f231ddaSDan Williams 				*status_ptr = SAS_DEVICE_UNKNOWN;
25596f231ddaSDan Williams 			else
25606f231ddaSDan Williams 				*status_ptr = SAS_ABORTED_TASK;
25616f231ddaSDan Williams 
256238d8879bSDan Williams 			set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
25636f231ddaSDan Williams 		} else {
25646f231ddaSDan Williams 			/* Task in the target is not done. */
25656f231ddaSDan Williams 			*response_ptr = SAS_TASK_UNDELIVERED;
25666f231ddaSDan Williams 
2567209fae14SDan Williams 			if (!idev)
25686f231ddaSDan Williams 				*status_ptr = SAS_DEVICE_UNKNOWN;
25696f231ddaSDan Williams 			else
2570d377f415SBart Van Assche 				*status_ptr = SAS_SAM_STAT_TASK_ABORTED;
25716f231ddaSDan Williams 
257238d8879bSDan Williams 			clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
25736f231ddaSDan Williams 		}
25746f231ddaSDan Williams 
25756f231ddaSDan Williams 		break;
25766f231ddaSDan Williams 
25776f231ddaSDan Williams 	case SCU_TASK_DONE_CRC_ERR:
25786f231ddaSDan Williams 	case SCU_TASK_DONE_NAK_CMD_ERR:
25796f231ddaSDan Williams 	case SCU_TASK_DONE_EXCESS_DATA:
25806f231ddaSDan Williams 	case SCU_TASK_DONE_UNEXP_FIS:
25816f231ddaSDan Williams 	/* Also SCU_TASK_DONE_UNEXP_RESP: */
25826f231ddaSDan Williams 	case SCU_TASK_DONE_VIIT_ENTRY_NV:       /* TODO - conditions? */
25836f231ddaSDan Williams 	case SCU_TASK_DONE_IIT_ENTRY_NV:        /* TODO - conditions? */
25846f231ddaSDan Williams 	case SCU_TASK_DONE_RNCNV_OUTBOUND:      /* TODO - conditions? */
25856f231ddaSDan Williams 		/* These are conditions in which the target
25866f231ddaSDan Williams 		 * has completed the task, so that no cleanup
25876f231ddaSDan Williams 		 * is necessary.
25886f231ddaSDan Williams 		 */
25896f231ddaSDan Williams 		*response_ptr = SAS_TASK_COMPLETE;
25906f231ddaSDan Williams 
25916f231ddaSDan Williams 		/* See if the device has been/is being stopped. Note
25926f231ddaSDan Williams 		 * that we ignore the quiesce state, since we are
25936f231ddaSDan Williams 		 * concerned about the actual device state.
25946f231ddaSDan Williams 		 */
2595209fae14SDan Williams 		if (!idev)
25966f231ddaSDan Williams 			*status_ptr = SAS_DEVICE_UNKNOWN;
25976f231ddaSDan Williams 		else
25986f231ddaSDan Williams 			*status_ptr = SAS_ABORTED_TASK;
25996f231ddaSDan Williams 
260038d8879bSDan Williams 		set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
26016f231ddaSDan Williams 		break;
26026f231ddaSDan Williams 
26036f231ddaSDan Williams 
26046f231ddaSDan Williams 	/* Note that the only open reject completion codes seen here will be
26056f231ddaSDan Williams 	 * abandon-class codes; all others are automatically retried in the SCU.
26066f231ddaSDan Williams 	 */
26076f231ddaSDan Williams 	case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION:
26086f231ddaSDan Williams 
26096f231ddaSDan Williams 		isci_request_set_open_reject_status(
26106f231ddaSDan Williams 			request, task, response_ptr, status_ptr,
261114aaa9f0SJeff Skirvin 			SAS_OREJ_WRONG_DEST);
26126f231ddaSDan Williams 		break;
26136f231ddaSDan Williams 
26146f231ddaSDan Williams 	case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
26156f231ddaSDan Williams 
26166f231ddaSDan Williams 		/* Note - the return of AB0 will change when
26176f231ddaSDan Williams 		 * libsas implements detection of zone violations.
26186f231ddaSDan Williams 		 */
26196f231ddaSDan Williams 		isci_request_set_open_reject_status(
26206f231ddaSDan Williams 			request, task, response_ptr, status_ptr,
262114aaa9f0SJeff Skirvin 			SAS_OREJ_RESV_AB0);
26226f231ddaSDan Williams 		break;
26236f231ddaSDan Williams 
26246f231ddaSDan Williams 	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
26256f231ddaSDan Williams 
26266f231ddaSDan Williams 		isci_request_set_open_reject_status(
26276f231ddaSDan Williams 			request, task, response_ptr, status_ptr,
262814aaa9f0SJeff Skirvin 			SAS_OREJ_RESV_AB1);
26296f231ddaSDan Williams 		break;
26306f231ddaSDan Williams 
26316f231ddaSDan Williams 	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
26326f231ddaSDan Williams 
26336f231ddaSDan Williams 		isci_request_set_open_reject_status(
26346f231ddaSDan Williams 			request, task, response_ptr, status_ptr,
263514aaa9f0SJeff Skirvin 			SAS_OREJ_RESV_AB2);
26366f231ddaSDan Williams 		break;
26376f231ddaSDan Williams 
26386f231ddaSDan Williams 	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
26396f231ddaSDan Williams 
26406f231ddaSDan Williams 		isci_request_set_open_reject_status(
26416f231ddaSDan Williams 			request, task, response_ptr, status_ptr,
264214aaa9f0SJeff Skirvin 			SAS_OREJ_RESV_AB3);
26436f231ddaSDan Williams 		break;
26446f231ddaSDan Williams 
26456f231ddaSDan Williams 	case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
26466f231ddaSDan Williams 
26476f231ddaSDan Williams 		isci_request_set_open_reject_status(
26486f231ddaSDan Williams 			request, task, response_ptr, status_ptr,
264914aaa9f0SJeff Skirvin 			SAS_OREJ_BAD_DEST);
26506f231ddaSDan Williams 		break;
26516f231ddaSDan Williams 
26526f231ddaSDan Williams 	case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY:
26536f231ddaSDan Williams 
26546f231ddaSDan Williams 		isci_request_set_open_reject_status(
26556f231ddaSDan Williams 			request, task, response_ptr, status_ptr,
265614aaa9f0SJeff Skirvin 			SAS_OREJ_STP_NORES);
26576f231ddaSDan Williams 		break;
26586f231ddaSDan Williams 
26596f231ddaSDan Williams 	case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED:
26606f231ddaSDan Williams 
26616f231ddaSDan Williams 		isci_request_set_open_reject_status(
26626f231ddaSDan Williams 			request, task, response_ptr, status_ptr,
266314aaa9f0SJeff Skirvin 			SAS_OREJ_EPROTO);
26646f231ddaSDan Williams 		break;
26656f231ddaSDan Williams 
26666f231ddaSDan Williams 	case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED:
26676f231ddaSDan Williams 
26686f231ddaSDan Williams 		isci_request_set_open_reject_status(
26696f231ddaSDan Williams 			request, task, response_ptr, status_ptr,
267014aaa9f0SJeff Skirvin 			SAS_OREJ_CONN_RATE);
26716f231ddaSDan Williams 		break;
26726f231ddaSDan Williams 
26736f231ddaSDan Williams 	case SCU_TASK_DONE_LL_R_ERR:
26746f231ddaSDan Williams 	/* Also SCU_TASK_DONE_ACK_NAK_TO: */
26756f231ddaSDan Williams 	case SCU_TASK_DONE_LL_PERR:
26766f231ddaSDan Williams 	case SCU_TASK_DONE_LL_SY_TERM:
26776f231ddaSDan Williams 	/* Also SCU_TASK_DONE_NAK_ERR:*/
26786f231ddaSDan Williams 	case SCU_TASK_DONE_LL_LF_TERM:
26796f231ddaSDan Williams 	/* Also SCU_TASK_DONE_DATA_LEN_ERR: */
26806f231ddaSDan Williams 	case SCU_TASK_DONE_LL_ABORT_ERR:
26816f231ddaSDan Williams 	case SCU_TASK_DONE_SEQ_INV_TYPE:
26826f231ddaSDan Williams 	/* Also SCU_TASK_DONE_UNEXP_XR: */
26836f231ddaSDan Williams 	case SCU_TASK_DONE_XR_IU_LEN_ERR:
26846f231ddaSDan Williams 	case SCU_TASK_DONE_INV_FIS_LEN:
26856f231ddaSDan Williams 	/* Also SCU_TASK_DONE_XR_WD_LEN: */
26866f231ddaSDan Williams 	case SCU_TASK_DONE_SDMA_ERR:
26876f231ddaSDan Williams 	case SCU_TASK_DONE_OFFSET_ERR:
26886f231ddaSDan Williams 	case SCU_TASK_DONE_MAX_PLD_ERR:
26896f231ddaSDan Williams 	case SCU_TASK_DONE_LF_ERR:
26906f231ddaSDan Williams 	case SCU_TASK_DONE_SMP_RESP_TO_ERR:  /* Escalate to dev reset? */
26916f231ddaSDan Williams 	case SCU_TASK_DONE_SMP_LL_RX_ERR:
26926f231ddaSDan Williams 	case SCU_TASK_DONE_UNEXP_DATA:
26936f231ddaSDan Williams 	case SCU_TASK_DONE_UNEXP_SDBFIS:
26946f231ddaSDan Williams 	case SCU_TASK_DONE_REG_ERR:
26956f231ddaSDan Williams 	case SCU_TASK_DONE_SDB_ERR:
26966f231ddaSDan Williams 	case SCU_TASK_DONE_TASK_ABORT:
26976f231ddaSDan Williams 	default:
26986f231ddaSDan Williams 		/* Task in the target is not done. */
26996f231ddaSDan Williams 		*response_ptr = SAS_TASK_UNDELIVERED;
2700d377f415SBart Van Assche 		*status_ptr = SAS_SAM_STAT_TASK_ABORTED;
2701cde76fbfSJeff Skirvin 
270214aaa9f0SJeff Skirvin 		if (task->task_proto == SAS_PROTOCOL_SMP)
270338d8879bSDan Williams 			set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
270414aaa9f0SJeff Skirvin 		else
270538d8879bSDan Williams 			clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
27066f231ddaSDan Williams 		break;
27076f231ddaSDan Williams 	}
27086f231ddaSDan Williams }
27096f231ddaSDan Williams 
isci_process_stp_response(struct sas_task * task,struct dev_to_host_fis * fis)27101a878284SDan Williams static void isci_process_stp_response(struct sas_task *task, struct dev_to_host_fis *fis)
271116ba7709SDan Williams {
271216ba7709SDan Williams 	struct task_status_struct *ts = &task->task_status;
271316ba7709SDan Williams 	struct ata_task_resp *resp = (void *)&ts->buf[0];
271416ba7709SDan Williams 
27151a878284SDan Williams 	resp->frame_len = sizeof(*fis);
27161a878284SDan Williams 	memcpy(resp->ending_fis, fis, sizeof(*fis));
271716ba7709SDan Williams 	ts->buf_valid_size = sizeof(*resp);
271816ba7709SDan Williams 
27192193b1b1SDan Williams 	/* If an error is flagged let libata decode the fis */
27202193b1b1SDan Williams 	if (ac_err_mask(fis->status))
272116ba7709SDan Williams 		ts->stat = SAS_PROTO_RESPONSE;
272216ba7709SDan Williams 	else
2723d377f415SBart Van Assche 		ts->stat = SAS_SAM_STAT_GOOD;
272416ba7709SDan Williams 
272516ba7709SDan Williams 	ts->resp = SAS_TASK_COMPLETE;
272616ba7709SDan Williams }
272716ba7709SDan Williams 
isci_request_io_request_complete(struct isci_host * ihost,struct isci_request * request,enum sci_io_status completion_status)2728d9dcb4baSDan Williams static void isci_request_io_request_complete(struct isci_host *ihost,
27296f231ddaSDan Williams 					     struct isci_request *request,
27306f231ddaSDan Williams 					     enum sci_io_status completion_status)
27316f231ddaSDan Williams {
27326f231ddaSDan Williams 	struct sas_task *task = isci_request_access_task(request);
27336f231ddaSDan Williams 	struct ssp_response_iu *resp_iu;
27346f231ddaSDan Williams 	unsigned long task_flags;
27350e2e2799SJeff Skirvin 	struct isci_remote_device *idev = request->target_device;
27366f231ddaSDan Williams 	enum service_response response = SAS_TASK_UNDELIVERED;
27376f231ddaSDan Williams 	enum exec_status status = SAS_ABORTED_TASK;
27386f231ddaSDan Williams 
2739d9dcb4baSDan Williams 	dev_dbg(&ihost->pdev->dev,
2740f8381807SJeff Skirvin 		"%s: request = %p, task = %p, "
27416f231ddaSDan Williams 		"task->data_dir = %d completion_status = 0x%x\n",
2742f8381807SJeff Skirvin 		__func__, request, task, task->data_dir, completion_status);
27436f231ddaSDan Williams 
2744a5fde225SJeff Skirvin 	/* The request is done from an SCU HW perspective. */
2745a5fde225SJeff Skirvin 
27466f231ddaSDan Williams 	/* This is an active request being completed from the core. */
27476f231ddaSDan Williams 	switch (completion_status) {
27486f231ddaSDan Williams 
27496f231ddaSDan Williams 	case SCI_IO_FAILURE_RESPONSE_VALID:
2750d9dcb4baSDan Williams 		dev_dbg(&ihost->pdev->dev,
27516f231ddaSDan Williams 			"%s: SCI_IO_FAILURE_RESPONSE_VALID (%p/%p)\n",
275214aaa9f0SJeff Skirvin 			__func__, request, task);
27536f231ddaSDan Williams 
27546f231ddaSDan Williams 		if (sas_protocol_ata(task->task_proto)) {
27551a878284SDan Williams 			isci_process_stp_response(task, &request->stp.rsp);
27566f231ddaSDan Williams 		} else if (SAS_PROTOCOL_SSP == task->task_proto) {
27576f231ddaSDan Williams 
27586f231ddaSDan Williams 			/* crack the iu response buffer. */
27595076a1a9SDan Williams 			resp_iu = &request->ssp.rsp;
27606f231ddaSDan Williams 			isci_request_process_response_iu(task, resp_iu,
2761d9dcb4baSDan Williams 							 &ihost->pdev->dev);
27626f231ddaSDan Williams 
27636f231ddaSDan Williams 		} else if (SAS_PROTOCOL_SMP == task->task_proto) {
27646f231ddaSDan Williams 
2765d9dcb4baSDan Williams 			dev_err(&ihost->pdev->dev,
27666f231ddaSDan Williams 				"%s: SCI_IO_FAILURE_RESPONSE_VALID: "
27676f231ddaSDan Williams 					"SAS_PROTOCOL_SMP protocol\n",
27686f231ddaSDan Williams 				__func__);
27696f231ddaSDan Williams 
27706f231ddaSDan Williams 		} else
2771d9dcb4baSDan Williams 			dev_err(&ihost->pdev->dev,
27726f231ddaSDan Williams 				"%s: unknown protocol\n", __func__);
27736f231ddaSDan Williams 
27746f231ddaSDan Williams 		/* use the task status set in the task struct by the
27756f231ddaSDan Williams 		* isci_request_process_response_iu call.
27766f231ddaSDan Williams 		*/
277738d8879bSDan Williams 		set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
27786f231ddaSDan Williams 		response = task->task_status.resp;
27796f231ddaSDan Williams 		status = task->task_status.stat;
27806f231ddaSDan Williams 		break;
27816f231ddaSDan Williams 
27826f231ddaSDan Williams 	case SCI_IO_SUCCESS:
27836f231ddaSDan Williams 	case SCI_IO_SUCCESS_IO_DONE_EARLY:
27846f231ddaSDan Williams 
27856f231ddaSDan Williams 		response = SAS_TASK_COMPLETE;
2786d377f415SBart Van Assche 		status   = SAS_SAM_STAT_GOOD;
278738d8879bSDan Williams 		set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
27886f231ddaSDan Williams 
278954b5e3a4SDan Williams 		if (completion_status == SCI_IO_SUCCESS_IO_DONE_EARLY) {
27906f231ddaSDan Williams 
27916f231ddaSDan Williams 			/* This was an SSP / STP / SATA transfer.
27926f231ddaSDan Williams 			* There is a possibility that less data than
27936f231ddaSDan Williams 			* the maximum was transferred.
27946f231ddaSDan Williams 			*/
27955076a1a9SDan Williams 			u32 transferred_length = sci_req_tx_bytes(request);
27966f231ddaSDan Williams 
27976f231ddaSDan Williams 			task->task_status.residual
27986f231ddaSDan Williams 				= task->total_xfer_len - transferred_length;
27996f231ddaSDan Williams 
28006f231ddaSDan Williams 			/* If there were residual bytes, call this an
28016f231ddaSDan Williams 			* underrun.
28026f231ddaSDan Williams 			*/
28036f231ddaSDan Williams 			if (task->task_status.residual != 0)
28046f231ddaSDan Williams 				status = SAS_DATA_UNDERRUN;
28056f231ddaSDan Williams 
2806d9dcb4baSDan Williams 			dev_dbg(&ihost->pdev->dev,
28076f231ddaSDan Williams 				"%s: SCI_IO_SUCCESS_IO_DONE_EARLY %d\n",
280814aaa9f0SJeff Skirvin 				__func__, status);
28096f231ddaSDan Williams 
28106f231ddaSDan Williams 		} else
281114aaa9f0SJeff Skirvin 			dev_dbg(&ihost->pdev->dev, "%s: SCI_IO_SUCCESS\n",
28126f231ddaSDan Williams 				__func__);
28136f231ddaSDan Williams 		break;
28146f231ddaSDan Williams 
28156f231ddaSDan Williams 	case SCI_IO_FAILURE_TERMINATED:
281614aaa9f0SJeff Skirvin 
2817d9dcb4baSDan Williams 		dev_dbg(&ihost->pdev->dev,
28186f231ddaSDan Williams 			"%s: SCI_IO_FAILURE_TERMINATED (%p/%p)\n",
281914aaa9f0SJeff Skirvin 			__func__, request, task);
28206f231ddaSDan Williams 
282114aaa9f0SJeff Skirvin 		/* The request was terminated explicitly. */
2822e3c84dfdSJeff Skirvin 		set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
28236f231ddaSDan Williams 		response = SAS_TASK_UNDELIVERED;
28246f231ddaSDan Williams 
28256f231ddaSDan Williams 		/* See if the device has been/is being stopped. Note
28266f231ddaSDan Williams 		* that we ignore the quiesce state, since we are
28276f231ddaSDan Williams 		* concerned about the actual device state.
28286f231ddaSDan Williams 		*/
2829209fae14SDan Williams 		if (!idev)
28306f231ddaSDan Williams 			status = SAS_DEVICE_UNKNOWN;
28316f231ddaSDan Williams 		else
28326f231ddaSDan Williams 			status = SAS_ABORTED_TASK;
28336f231ddaSDan Williams 		break;
28346f231ddaSDan Williams 
28356f231ddaSDan Williams 	case SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR:
28366f231ddaSDan Williams 
283714aaa9f0SJeff Skirvin 		isci_request_handle_controller_specific_errors(idev, request,
283814aaa9f0SJeff Skirvin 							       task, &response,
283914aaa9f0SJeff Skirvin 							       &status);
28406f231ddaSDan Williams 		break;
28416f231ddaSDan Williams 
28426f231ddaSDan Williams 	case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED:
28436f231ddaSDan Williams 		/* This is a special case, in that the I/O completion
28446f231ddaSDan Williams 		* is telling us that the device needs a reset.
28456f231ddaSDan Williams 		* In order for the device reset condition to be
28466f231ddaSDan Williams 		* noticed, the I/O has to be handled in the error
28476f231ddaSDan Williams 		* handler.  Set the reset flag and cause the
28486f231ddaSDan Williams 		* SCSI error thread to be scheduled.
28496f231ddaSDan Williams 		*/
28506f231ddaSDan Williams 		spin_lock_irqsave(&task->task_state_lock, task_flags);
28516f231ddaSDan Williams 		task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
28526f231ddaSDan Williams 		spin_unlock_irqrestore(&task->task_state_lock, task_flags);
28536f231ddaSDan Williams 
2854aa145102SJeff Skirvin 		/* Fail the I/O. */
2855aa145102SJeff Skirvin 		response = SAS_TASK_UNDELIVERED;
2856d377f415SBart Van Assche 		status = SAS_SAM_STAT_TASK_ABORTED;
2857aa145102SJeff Skirvin 
285838d8879bSDan Williams 		clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
28596f231ddaSDan Williams 		break;
28606f231ddaSDan Williams 
2861cde76fbfSJeff Skirvin 	case SCI_FAILURE_RETRY_REQUIRED:
2862cde76fbfSJeff Skirvin 
2863cde76fbfSJeff Skirvin 		/* Fail the I/O so it can be retried. */
2864cde76fbfSJeff Skirvin 		response = SAS_TASK_UNDELIVERED;
2865209fae14SDan Williams 		if (!idev)
2866cde76fbfSJeff Skirvin 			status = SAS_DEVICE_UNKNOWN;
2867cde76fbfSJeff Skirvin 		else
2868cde76fbfSJeff Skirvin 			status = SAS_ABORTED_TASK;
2869cde76fbfSJeff Skirvin 
287038d8879bSDan Williams 		set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
2871cde76fbfSJeff Skirvin 		break;
2872cde76fbfSJeff Skirvin 
2873cde76fbfSJeff Skirvin 
28746f231ddaSDan Williams 	default:
28756f231ddaSDan Williams 		/* Catch any otherwise unhandled error codes here. */
2876a8a0a133SDan Williams 		dev_dbg(&ihost->pdev->dev,
28776f231ddaSDan Williams 			"%s: invalid completion code: 0x%x - "
28786f231ddaSDan Williams 				"isci_request = %p\n",
28796f231ddaSDan Williams 			__func__, completion_status, request);
28806f231ddaSDan Williams 
28816f231ddaSDan Williams 		response = SAS_TASK_UNDELIVERED;
28826f231ddaSDan Williams 
28836f231ddaSDan Williams 		/* See if the device has been/is being stopped. Note
28846f231ddaSDan Williams 		* that we ignore the quiesce state, since we are
28856f231ddaSDan Williams 		* concerned about the actual device state.
28866f231ddaSDan Williams 		*/
2887209fae14SDan Williams 		if (!idev)
28886f231ddaSDan Williams 			status = SAS_DEVICE_UNKNOWN;
28896f231ddaSDan Williams 		else
28906f231ddaSDan Williams 			status = SAS_ABORTED_TASK;
28916f231ddaSDan Williams 
289214aaa9f0SJeff Skirvin 		if (SAS_PROTOCOL_SMP == task->task_proto)
289338d8879bSDan Williams 			set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
289414aaa9f0SJeff Skirvin 		else
289538d8879bSDan Williams 			clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
28966f231ddaSDan Williams 		break;
28976f231ddaSDan Williams 	}
28986f231ddaSDan Williams 
2899ddcc7e34SDan Williams 	switch (task->task_proto) {
2900ddcc7e34SDan Williams 	case SAS_PROTOCOL_SSP:
2901ddcc7e34SDan Williams 		if (task->data_dir == DMA_NONE)
2902ddcc7e34SDan Williams 			break;
2903ddcc7e34SDan Williams 		if (task->num_scatter == 0)
2904ddcc7e34SDan Williams 			/* 0 indicates a single dma address */
2905d9dcb4baSDan Williams 			dma_unmap_single(&ihost->pdev->dev,
2906ddcc7e34SDan Williams 					 request->zero_scatter_daddr,
2907ddcc7e34SDan Williams 					 task->total_xfer_len, task->data_dir);
2908ddcc7e34SDan Williams 		else  /* unmap the sgl dma addresses */
2909d9dcb4baSDan Williams 			dma_unmap_sg(&ihost->pdev->dev, task->scatter,
2910ddcc7e34SDan Williams 				     request->num_sg_entries, task->data_dir);
2911ddcc7e34SDan Williams 		break;
2912e9bf7095SDan Williams 	case SAS_PROTOCOL_SMP: {
2913e9bf7095SDan Williams 		struct scatterlist *sg = &task->smp_task.smp_req;
2914e9bf7095SDan Williams 		struct smp_req *smp_req;
2915e9bf7095SDan Williams 		void *kaddr;
2916e9bf7095SDan Williams 
2917d9dcb4baSDan Williams 		dma_unmap_sg(&ihost->pdev->dev, sg, 1, DMA_TO_DEVICE);
2918e9bf7095SDan Williams 
2919e9bf7095SDan Williams 		/* need to swab it back in case the command buffer is re-used */
292077dfce07SCong Wang 		kaddr = kmap_atomic(sg_page(sg));
2921e9bf7095SDan Williams 		smp_req = kaddr + sg->offset;
2922e9bf7095SDan Williams 		sci_swab32_cpy(smp_req, smp_req, sg->length / sizeof(u32));
292377dfce07SCong Wang 		kunmap_atomic(kaddr);
2924e9bf7095SDan Williams 		break;
2925e9bf7095SDan Williams 	}
2926ddcc7e34SDan Williams 	default:
2927ddcc7e34SDan Williams 		break;
2928ddcc7e34SDan Williams 	}
29296f231ddaSDan Williams 
293014aaa9f0SJeff Skirvin 	spin_lock_irqsave(&task->task_state_lock, task_flags);
293114aaa9f0SJeff Skirvin 
293214aaa9f0SJeff Skirvin 	task->task_status.resp = response;
293314aaa9f0SJeff Skirvin 	task->task_status.stat = status;
293414aaa9f0SJeff Skirvin 
293514aaa9f0SJeff Skirvin 	if (test_bit(IREQ_COMPLETE_IN_TARGET, &request->flags)) {
293614aaa9f0SJeff Skirvin 		/* Normal notification (task_done) */
293714aaa9f0SJeff Skirvin 		task->task_state_flags |= SAS_TASK_STATE_DONE;
293826fc0ea7SJohn Garry 		task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
293914aaa9f0SJeff Skirvin 	}
294014aaa9f0SJeff Skirvin 	spin_unlock_irqrestore(&task->task_state_lock, task_flags);
294114aaa9f0SJeff Skirvin 
29426f231ddaSDan Williams 	/* complete the io request to the core. */
294389a7301fSDan Williams 	sci_controller_complete_io(ihost, request->target_device, request);
2944209fae14SDan Williams 
294567ea838dSDan Williams 	/* set terminated handle so it cannot be completed or
29466f231ddaSDan Williams 	 * terminated again, and to cause any calls into abort
29476f231ddaSDan Williams 	 * task to recognize the already completed case.
29486f231ddaSDan Williams 	 */
294938d8879bSDan Williams 	set_bit(IREQ_TERMINATED, &request->flags);
2950f8381807SJeff Skirvin 
2951f8381807SJeff Skirvin 	ireq_done(ihost, request, task);
29526f231ddaSDan Williams }
2953f1f52e75SDan Williams 
sci_request_started_state_enter(struct sci_base_state_machine * sm)295489a7301fSDan Williams static void sci_request_started_state_enter(struct sci_base_state_machine *sm)
2955f1f52e75SDan Williams {
29565076a1a9SDan Williams 	struct isci_request *ireq = container_of(sm, typeof(*ireq), sm);
295778a6f06eSDan Williams 	struct domain_device *dev = ireq->target_device->domain_dev;
2958b50102d3SDan Williams 	enum sci_base_request_states state;
2959c72086e3SDan Williams 	struct sas_task *task;
2960c72086e3SDan Williams 
2961c72086e3SDan Williams 	/* XXX as hch said always creating an internal sas_task for tmf
2962c72086e3SDan Williams 	 * requests would simplify the driver
2963c72086e3SDan Williams 	 */
29643b34c169SJeff Skirvin 	task = (test_bit(IREQ_TMF, &ireq->flags)) ? NULL : isci_request_access_task(ireq);
2965f1f52e75SDan Williams 
29665dec6f4eSDan Williams 	/* all unaccelerated request types (non ssp or ncq) handled with
29675dec6f4eSDan Williams 	 * substates
2968f139303dSDan Williams 	 */
2969aa9f8328SJames Bottomley 	if (!task && dev->dev_type == SAS_END_DEVICE) {
2970b50102d3SDan Williams 		state = SCI_REQ_TASK_WAIT_TC_COMP;
2971c72086e3SDan Williams 	} else if (task && task->task_proto == SAS_PROTOCOL_SMP) {
2972b50102d3SDan Williams 		state = SCI_REQ_SMP_WAIT_RESP;
29735dec6f4eSDan Williams 	} else if (task && sas_protocol_ata(task->task_proto) &&
29745dec6f4eSDan Williams 		   !task->ata_task.use_ncq) {
29751cbd772dSHannes Reinecke 		if (dev->sata_dev.class == ATA_DEV_ATAPI &&
2976b50102d3SDan Williams 			task->ata_task.fis.command == ATA_CMD_PACKET) {
2977b50102d3SDan Williams 			state = SCI_REQ_ATAPI_WAIT_H2D;
2978b50102d3SDan Williams 		} else if (task->data_dir == DMA_NONE) {
2979e301370aSEdmund Nadolski 			state = SCI_REQ_STP_NON_DATA_WAIT_H2D;
2980b50102d3SDan Williams 		} else if (task->ata_task.dma_xfer) {
2981e301370aSEdmund Nadolski 			state = SCI_REQ_STP_UDMA_WAIT_TC_COMP;
2982b50102d3SDan Williams 		} else /* PIO */ {
2983e301370aSEdmund Nadolski 			state = SCI_REQ_STP_PIO_WAIT_H2D;
29845dec6f4eSDan Williams 		}
2985b50102d3SDan Williams 	} else {
2986b50102d3SDan Williams 		/* SSP or NCQ are fully accelerated, no substates */
2987b50102d3SDan Williams 		return;
2988b50102d3SDan Williams 	}
2989b50102d3SDan Williams 	sci_change_state(sm, state);
2990f1f52e75SDan Williams }
2991f1f52e75SDan Williams 
sci_request_completed_state_enter(struct sci_base_state_machine * sm)299289a7301fSDan Williams static void sci_request_completed_state_enter(struct sci_base_state_machine *sm)
2993f1f52e75SDan Williams {
29945076a1a9SDan Williams 	struct isci_request *ireq = container_of(sm, typeof(*ireq), sm);
2995d9dcb4baSDan Williams 	struct isci_host *ihost = ireq->owning_controller;
2996f1f52e75SDan Williams 
2997f1f52e75SDan Williams 	/* Tell the SCI_USER that the IO request is complete */
299838d8879bSDan Williams 	if (!test_bit(IREQ_TMF, &ireq->flags))
2999f1f52e75SDan Williams 		isci_request_io_request_complete(ihost, ireq,
30005076a1a9SDan Williams 						 ireq->sci_status);
3001f1f52e75SDan Williams 	else
30025076a1a9SDan Williams 		isci_task_request_complete(ihost, ireq, ireq->sci_status);
3003f1f52e75SDan Williams }
3004f1f52e75SDan Williams 
sci_request_aborting_state_enter(struct sci_base_state_machine * sm)300589a7301fSDan Williams static void sci_request_aborting_state_enter(struct sci_base_state_machine *sm)
3006f1f52e75SDan Williams {
30075076a1a9SDan Williams 	struct isci_request *ireq = container_of(sm, typeof(*ireq), sm);
3008f1f52e75SDan Williams 
3009f1f52e75SDan Williams 	/* Setting the abort bit in the Task Context is required by the silicon. */
30105076a1a9SDan Williams 	ireq->tc->abort = 1;
3011c72086e3SDan Williams }
3012c72086e3SDan Williams 
sci_stp_request_started_non_data_await_h2d_completion_enter(struct sci_base_state_machine * sm)301389a7301fSDan Williams static void sci_stp_request_started_non_data_await_h2d_completion_enter(struct sci_base_state_machine *sm)
30145dec6f4eSDan Williams {
30155076a1a9SDan Williams 	struct isci_request *ireq = container_of(sm, typeof(*ireq), sm);
30165dec6f4eSDan Williams 
301734a99158SDan Williams 	ireq->target_device->working_request = ireq;
30185dec6f4eSDan Williams }
30195dec6f4eSDan Williams 
sci_stp_request_started_pio_await_h2d_completion_enter(struct sci_base_state_machine * sm)302089a7301fSDan Williams static void sci_stp_request_started_pio_await_h2d_completion_enter(struct sci_base_state_machine *sm)
30215dec6f4eSDan Williams {
30225076a1a9SDan Williams 	struct isci_request *ireq = container_of(sm, typeof(*ireq), sm);
30235dec6f4eSDan Williams 
302434a99158SDan Williams 	ireq->target_device->working_request = ireq;
30255dec6f4eSDan Williams }
30265dec6f4eSDan Williams 
302789a7301fSDan Williams static const struct sci_base_state sci_request_state_table[] = {
3028e301370aSEdmund Nadolski 	[SCI_REQ_INIT] = { },
3029e301370aSEdmund Nadolski 	[SCI_REQ_CONSTRUCTED] = { },
3030e301370aSEdmund Nadolski 	[SCI_REQ_STARTED] = {
303189a7301fSDan Williams 		.enter_state = sci_request_started_state_enter,
30325dec6f4eSDan Williams 	},
3033e301370aSEdmund Nadolski 	[SCI_REQ_STP_NON_DATA_WAIT_H2D] = {
303489a7301fSDan Williams 		.enter_state = sci_stp_request_started_non_data_await_h2d_completion_enter,
30355dec6f4eSDan Williams 	},
3036e301370aSEdmund Nadolski 	[SCI_REQ_STP_NON_DATA_WAIT_D2H] = { },
3037e301370aSEdmund Nadolski 	[SCI_REQ_STP_PIO_WAIT_H2D] = {
303889a7301fSDan Williams 		.enter_state = sci_stp_request_started_pio_await_h2d_completion_enter,
30395dec6f4eSDan Williams 	},
3040e301370aSEdmund Nadolski 	[SCI_REQ_STP_PIO_WAIT_FRAME] = { },
3041e301370aSEdmund Nadolski 	[SCI_REQ_STP_PIO_DATA_IN] = { },
3042e301370aSEdmund Nadolski 	[SCI_REQ_STP_PIO_DATA_OUT] = { },
3043e301370aSEdmund Nadolski 	[SCI_REQ_STP_UDMA_WAIT_TC_COMP] = { },
3044e301370aSEdmund Nadolski 	[SCI_REQ_STP_UDMA_WAIT_D2H] = { },
3045e301370aSEdmund Nadolski 	[SCI_REQ_TASK_WAIT_TC_COMP] = { },
3046e301370aSEdmund Nadolski 	[SCI_REQ_TASK_WAIT_TC_RESP] = { },
3047e301370aSEdmund Nadolski 	[SCI_REQ_SMP_WAIT_RESP] = { },
3048e301370aSEdmund Nadolski 	[SCI_REQ_SMP_WAIT_TC_COMP] = { },
3049b50102d3SDan Williams 	[SCI_REQ_ATAPI_WAIT_H2D] = { },
3050b50102d3SDan Williams 	[SCI_REQ_ATAPI_WAIT_PIO_SETUP] = { },
3051b50102d3SDan Williams 	[SCI_REQ_ATAPI_WAIT_D2H] = { },
3052b50102d3SDan Williams 	[SCI_REQ_ATAPI_WAIT_TC_COMP] = { },
3053e301370aSEdmund Nadolski 	[SCI_REQ_COMPLETED] = {
305489a7301fSDan Williams 		.enter_state = sci_request_completed_state_enter,
3055f1f52e75SDan Williams 	},
3056e301370aSEdmund Nadolski 	[SCI_REQ_ABORTING] = {
305789a7301fSDan Williams 		.enter_state = sci_request_aborting_state_enter,
3058f1f52e75SDan Williams 	},
3059e301370aSEdmund Nadolski 	[SCI_REQ_FINAL] = { },
3060f1f52e75SDan Williams };
3061f1f52e75SDan Williams 
3062e301370aSEdmund Nadolski static void
sci_general_request_construct(struct isci_host * ihost,struct isci_remote_device * idev,struct isci_request * ireq)306389a7301fSDan Williams sci_general_request_construct(struct isci_host *ihost,
306478a6f06eSDan Williams 				   struct isci_remote_device *idev,
30655076a1a9SDan Williams 				   struct isci_request *ireq)
3066f1f52e75SDan Williams {
306789a7301fSDan Williams 	sci_init_sm(&ireq->sm, sci_request_state_table, SCI_REQ_INIT);
3068f1f52e75SDan Williams 
306978a6f06eSDan Williams 	ireq->target_device = idev;
3070c79dd80dSDan Williams 	ireq->protocol = SAS_PROTOCOL_NONE;
30715076a1a9SDan Williams 	ireq->saved_rx_frame_index = SCU_INVALID_FRAME_INDEX;
3072f1f52e75SDan Williams 
30735076a1a9SDan Williams 	ireq->sci_status   = SCI_SUCCESS;
30745076a1a9SDan Williams 	ireq->scu_status   = 0;
30755076a1a9SDan Williams 	ireq->post_context = 0xFFFFFFFF;
3076f1f52e75SDan Williams }
3077f1f52e75SDan Williams 
3078f1f52e75SDan Williams static enum sci_status
sci_io_request_construct(struct isci_host * ihost,struct isci_remote_device * idev,struct isci_request * ireq)307989a7301fSDan Williams sci_io_request_construct(struct isci_host *ihost,
308078a6f06eSDan Williams 			  struct isci_remote_device *idev,
30815076a1a9SDan Williams 			  struct isci_request *ireq)
3082f1f52e75SDan Williams {
308378a6f06eSDan Williams 	struct domain_device *dev = idev->domain_dev;
3084f1f52e75SDan Williams 	enum sci_status status = SCI_SUCCESS;
3085f1f52e75SDan Williams 
3086f1f52e75SDan Williams 	/* Build the common part of the request */
308789a7301fSDan Williams 	sci_general_request_construct(ihost, idev, ireq);
3088f1f52e75SDan Williams 
308978a6f06eSDan Williams 	if (idev->rnc.remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX)
3090f1f52e75SDan Williams 		return SCI_FAILURE_INVALID_REMOTE_DEVICE;
3091f1f52e75SDan Williams 
3092aa9f8328SJames Bottomley 	if (dev->dev_type == SAS_END_DEVICE)
3093c72086e3SDan Williams 		/* pass */;
309411cc5183SDan Williams 	else if (dev_is_sata(dev))
30955076a1a9SDan Williams 		memset(&ireq->stp.cmd, 0, sizeof(ireq->stp.cmd));
3096924a3541SJohn Garry 	else if (dev_is_expander(dev->dev_type))
3097e9bf7095SDan Williams 		/* pass */;
3098c72086e3SDan Williams 	else
3099c72086e3SDan Williams 		return SCI_FAILURE_UNSUPPORTED_PROTOCOL;
3100f1f52e75SDan Williams 
31015076a1a9SDan Williams 	memset(ireq->tc, 0, offsetof(struct scu_task_context, sgl_pair_ab));
3102f1f52e75SDan Williams 
3103f1f52e75SDan Williams 	return status;
3104f1f52e75SDan Williams }
3105f1f52e75SDan Williams 
sci_task_request_construct(struct isci_host * ihost,struct isci_remote_device * idev,u16 io_tag,struct isci_request * ireq)310689a7301fSDan Williams enum sci_status sci_task_request_construct(struct isci_host *ihost,
310778a6f06eSDan Williams 					    struct isci_remote_device *idev,
31085076a1a9SDan Williams 					    u16 io_tag, struct isci_request *ireq)
3109f1f52e75SDan Williams {
311078a6f06eSDan Williams 	struct domain_device *dev = idev->domain_dev;
3111f1f52e75SDan Williams 	enum sci_status status = SCI_SUCCESS;
3112f1f52e75SDan Williams 
3113f1f52e75SDan Williams 	/* Build the common part of the request */
311489a7301fSDan Williams 	sci_general_request_construct(ihost, idev, ireq);
3115f1f52e75SDan Williams 
3116aa9f8328SJames Bottomley 	if (dev->dev_type == SAS_END_DEVICE || dev_is_sata(dev)) {
31175076a1a9SDan Williams 		set_bit(IREQ_TMF, &ireq->flags);
31185076a1a9SDan Williams 		memset(ireq->tc, 0, sizeof(struct scu_task_context));
311928de92beSJeff Skirvin 
312028de92beSJeff Skirvin 		/* Set the protocol indicator. */
312128de92beSJeff Skirvin 		if (dev_is_sata(dev))
312228de92beSJeff Skirvin 			ireq->protocol = SAS_PROTOCOL_STP;
312328de92beSJeff Skirvin 		else
312428de92beSJeff Skirvin 			ireq->protocol = SAS_PROTOCOL_SSP;
3125c72086e3SDan Williams 	} else
3126c72086e3SDan Williams 		status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
3127f1f52e75SDan Williams 
3128f1f52e75SDan Williams 	return status;
3129f1f52e75SDan Williams }
3130f1f52e75SDan Williams 
isci_request_ssp_request_construct(struct isci_request * request)3131f1f52e75SDan Williams static enum sci_status isci_request_ssp_request_construct(
3132f1f52e75SDan Williams 	struct isci_request *request)
3133f1f52e75SDan Williams {
3134f1f52e75SDan Williams 	enum sci_status status;
3135f1f52e75SDan Williams 
3136f1f52e75SDan Williams 	dev_dbg(&request->isci_host->pdev->dev,
3137f1f52e75SDan Williams 		"%s: request = %p\n",
3138f1f52e75SDan Williams 		__func__,
3139f1f52e75SDan Williams 		request);
314089a7301fSDan Williams 	status = sci_io_request_construct_basic_ssp(request);
3141f1f52e75SDan Williams 	return status;
3142f1f52e75SDan Williams }
3143f1f52e75SDan Williams 
isci_request_stp_request_construct(struct isci_request * ireq)314416ba7709SDan Williams static enum sci_status isci_request_stp_request_construct(struct isci_request *ireq)
3145f1f52e75SDan Williams {
314616ba7709SDan Williams 	struct sas_task *task = isci_request_access_task(ireq);
314716ba7709SDan Williams 	struct host_to_dev_fis *fis = &ireq->stp.cmd;
314816ba7709SDan Williams 	struct ata_queued_cmd *qc = task->uldd_task;
3149f1f52e75SDan Williams 	enum sci_status status;
3150f1f52e75SDan Williams 
315116ba7709SDan Williams 	dev_dbg(&ireq->isci_host->pdev->dev,
315216ba7709SDan Williams 		"%s: ireq = %p\n",
3153f1f52e75SDan Williams 		__func__,
315416ba7709SDan Williams 		ireq);
3155f1f52e75SDan Williams 
315616ba7709SDan Williams 	memcpy(fis, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
315716ba7709SDan Williams 	if (!task->ata_task.device_control_reg_update)
315816ba7709SDan Williams 		fis->flags |= 0x80;
315916ba7709SDan Williams 	fis->flags &= 0xF0;
3160f1f52e75SDan Williams 
316116ba7709SDan Williams 	status = sci_io_request_construct_basic_sata(ireq);
3162f1f52e75SDan Williams 
316316ba7709SDan Williams 	if (qc && (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
3164ef026b18SHannes Reinecke 		   qc->tf.command == ATA_CMD_FPDMA_READ ||
3165ef026b18SHannes Reinecke 		   qc->tf.command == ATA_CMD_FPDMA_RECV ||
3166661ce1f0SHannes Reinecke 		   qc->tf.command == ATA_CMD_FPDMA_SEND ||
3167661ce1f0SHannes Reinecke 		   qc->tf.command == ATA_CMD_NCQ_NON_DATA)) {
316816ba7709SDan Williams 		fis->sector_count = qc->tag << 3;
316916ba7709SDan Williams 		ireq->tc->type.stp.ncq_tag = qc->tag;
3170f1f52e75SDan Williams 	}
3171f1f52e75SDan Williams 
3172f1f52e75SDan Williams 	return status;
3173f1f52e75SDan Williams }
3174f1f52e75SDan Williams 
3175e9bf7095SDan Williams static enum sci_status
sci_io_request_construct_smp(struct device * dev,struct isci_request * ireq,struct sas_task * task)317689a7301fSDan Williams sci_io_request_construct_smp(struct device *dev,
31775076a1a9SDan Williams 			      struct isci_request *ireq,
3178e9bf7095SDan Williams 			      struct sas_task *task)
3179c72086e3SDan Williams {
3180e9bf7095SDan Williams 	struct scatterlist *sg = &task->smp_task.smp_req;
318178a6f06eSDan Williams 	struct isci_remote_device *idev;
3182c72086e3SDan Williams 	struct scu_task_context *task_context;
3183ffe191c9SDan Williams 	struct isci_port *iport;
3184e9bf7095SDan Williams 	struct smp_req *smp_req;
3185e9bf7095SDan Williams 	void *kaddr;
3186e9bf7095SDan Williams 	u8 req_len;
3187e9bf7095SDan Williams 	u32 cmd;
3188e9bf7095SDan Williams 
318977dfce07SCong Wang 	kaddr = kmap_atomic(sg_page(sg));
3190e9bf7095SDan Williams 	smp_req = kaddr + sg->offset;
3191e9bf7095SDan Williams 	/*
3192e9bf7095SDan Williams 	 * Look at the SMP requests' header fields; for certain SAS 1.x SMP
3193e9bf7095SDan Williams 	 * functions under SAS 2.0, a zero request length really indicates
3194e9bf7095SDan Williams 	 * a non-zero default length.
3195e9bf7095SDan Williams 	 */
3196e9bf7095SDan Williams 	if (smp_req->req_len == 0) {
3197e9bf7095SDan Williams 		switch (smp_req->func) {
3198e9bf7095SDan Williams 		case SMP_DISCOVER:
3199e9bf7095SDan Williams 		case SMP_REPORT_PHY_ERR_LOG:
3200e9bf7095SDan Williams 		case SMP_REPORT_PHY_SATA:
3201e9bf7095SDan Williams 		case SMP_REPORT_ROUTE_INFO:
3202e9bf7095SDan Williams 			smp_req->req_len = 2;
3203e9bf7095SDan Williams 			break;
3204e9bf7095SDan Williams 		case SMP_CONF_ROUTE_INFO:
3205e9bf7095SDan Williams 		case SMP_PHY_CONTROL:
3206e9bf7095SDan Williams 		case SMP_PHY_TEST_FUNCTION:
3207e9bf7095SDan Williams 			smp_req->req_len = 9;
3208e9bf7095SDan Williams 			break;
3209e9bf7095SDan Williams 			/* Default - zero is a valid default for 2.0. */
3210e9bf7095SDan Williams 		}
3211e9bf7095SDan Williams 	}
3212e9bf7095SDan Williams 	req_len = smp_req->req_len;
3213e9bf7095SDan Williams 	sci_swab32_cpy(smp_req, smp_req, sg->length / sizeof(u32));
3214e9bf7095SDan Williams 	cmd = *(u32 *) smp_req;
321577dfce07SCong Wang 	kunmap_atomic(kaddr);
3216e9bf7095SDan Williams 
3217e9bf7095SDan Williams 	if (!dma_map_sg(dev, sg, 1, DMA_TO_DEVICE))
3218e9bf7095SDan Williams 		return SCI_FAILURE;
3219e9bf7095SDan Williams 
3220c79dd80dSDan Williams 	ireq->protocol = SAS_PROTOCOL_SMP;
3221c72086e3SDan Williams 
3222c72086e3SDan Williams 	/* byte swap the smp request. */
3223c72086e3SDan Williams 
32245076a1a9SDan Williams 	task_context = ireq->tc;
3225c72086e3SDan Williams 
322634a99158SDan Williams 	idev = ireq->target_device;
322734a99158SDan Williams 	iport = idev->owning_port;
3228c72086e3SDan Williams 
3229c72086e3SDan Williams 	/*
3230881a9a54SGeert Uytterhoeven 	 * Fill in the TC with its required data
3231c72086e3SDan Williams 	 * 00h
3232c72086e3SDan Williams 	 */
3233c72086e3SDan Williams 	task_context->priority = 0;
3234c72086e3SDan Williams 	task_context->initiator_request = 1;
323578a6f06eSDan Williams 	task_context->connection_rate = idev->connection_rate;
323634a99158SDan Williams 	task_context->protocol_engine_index = ISCI_PEG;
323734a99158SDan Williams 	task_context->logical_port_index = iport->physical_port_index;
3238c72086e3SDan Williams 	task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SMP;
3239c72086e3SDan Williams 	task_context->abort = 0;
3240c72086e3SDan Williams 	task_context->valid = SCU_TASK_CONTEXT_VALID;
3241c72086e3SDan Williams 	task_context->context_type = SCU_TASK_CONTEXT_TYPE;
3242c72086e3SDan Williams 
3243c72086e3SDan Williams 	/* 04h */
324478a6f06eSDan Williams 	task_context->remote_node_index = idev->rnc.remote_node_index;
3245c72086e3SDan Williams 	task_context->command_code = 0;
3246c72086e3SDan Williams 	task_context->task_type = SCU_TASK_TYPE_SMP_REQUEST;
3247c72086e3SDan Williams 
3248c72086e3SDan Williams 	/* 08h */
3249c72086e3SDan Williams 	task_context->link_layer_control = 0;
3250c72086e3SDan Williams 	task_context->do_not_dma_ssp_good_response = 1;
3251c72086e3SDan Williams 	task_context->strict_ordering = 0;
3252c72086e3SDan Williams 	task_context->control_frame = 1;
3253c72086e3SDan Williams 	task_context->timeout_enable = 0;
3254c72086e3SDan Williams 	task_context->block_guard_enable = 0;
3255c72086e3SDan Williams 
3256c72086e3SDan Williams 	/* 0ch */
3257c72086e3SDan Williams 	task_context->address_modifier = 0;
3258c72086e3SDan Williams 
3259c72086e3SDan Williams 	/* 10h */
326077d67385SDave Jiang 	task_context->ssp_command_iu_length = req_len;
3261c72086e3SDan Williams 
3262c72086e3SDan Williams 	/* 14h */
3263c72086e3SDan Williams 	task_context->transfer_length_bytes = 0;
3264c72086e3SDan Williams 
3265c72086e3SDan Williams 	/*
3266c72086e3SDan Williams 	 * 18h ~ 30h, protocol specific
3267c72086e3SDan Williams 	 * since commandIU has been build by framework at this point, we just
3268c72086e3SDan Williams 	 * copy the frist DWord from command IU to this location. */
3269e9bf7095SDan Williams 	memcpy(&task_context->type.smp, &cmd, sizeof(u32));
3270c72086e3SDan Williams 
3271c72086e3SDan Williams 	/*
3272c72086e3SDan Williams 	 * 40h
3273c72086e3SDan Williams 	 * "For SMP you could program it to zero. We would prefer that way
3274c72086e3SDan Williams 	 * so that done code will be consistent." - Venki
3275c72086e3SDan Williams 	 */
3276c72086e3SDan Williams 	task_context->task_phase = 0;
3277c72086e3SDan Williams 
32785076a1a9SDan Williams 	ireq->post_context = (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC |
327934a99158SDan Williams 			      (ISCI_PEG << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) |
328034a99158SDan Williams 			       (iport->physical_port_index <<
3281c72086e3SDan Williams 				SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) |
32825076a1a9SDan Williams 			      ISCI_TAG_TCI(ireq->io_tag));
3283c72086e3SDan Williams 	/*
3284c72086e3SDan Williams 	 * Copy the physical address for the command buffer to the SCU Task
3285c72086e3SDan Williams 	 * Context command buffer should not contain command header.
3286c72086e3SDan Williams 	 */
3287e9bf7095SDan Williams 	task_context->command_iu_upper = upper_32_bits(sg_dma_address(sg));
3288e9bf7095SDan Williams 	task_context->command_iu_lower = lower_32_bits(sg_dma_address(sg) + sizeof(u32));
3289c72086e3SDan Williams 
3290c72086e3SDan Williams 	/* SMP response comes as UF, so no need to set response IU address. */
3291c72086e3SDan Williams 	task_context->response_iu_upper = 0;
3292c72086e3SDan Williams 	task_context->response_iu_lower = 0;
3293c72086e3SDan Williams 
32945076a1a9SDan Williams 	sci_change_state(&ireq->sm, SCI_REQ_CONSTRUCTED);
3295c72086e3SDan Williams 
3296c72086e3SDan Williams 	return SCI_SUCCESS;
3297c72086e3SDan Williams }
3298c72086e3SDan Williams 
3299c72086e3SDan Williams /*
3300f1f52e75SDan Williams  * isci_smp_request_build() - This function builds the smp request.
3301f1f52e75SDan Williams  * @ireq: This parameter points to the isci_request allocated in the
3302f1f52e75SDan Williams  *    request construct function.
3303f1f52e75SDan Williams  *
3304f1f52e75SDan Williams  * SCI_SUCCESS on successfull completion, or specific failure code.
3305f1f52e75SDan Williams  */
isci_smp_request_build(struct isci_request * ireq)3306f1f52e75SDan Williams static enum sci_status isci_smp_request_build(struct isci_request *ireq)
3307f1f52e75SDan Williams {
3308f1f52e75SDan Williams 	struct sas_task *task = isci_request_access_task(ireq);
3309e9bf7095SDan Williams 	struct device *dev = &ireq->isci_host->pdev->dev;
3310e9bf7095SDan Williams 	enum sci_status status = SCI_FAILURE;
3311f1f52e75SDan Williams 
331289a7301fSDan Williams 	status = sci_io_request_construct_smp(dev, ireq, task);
3313f1f52e75SDan Williams 	if (status != SCI_SUCCESS)
3314a8a0a133SDan Williams 		dev_dbg(&ireq->isci_host->pdev->dev,
3315f1f52e75SDan Williams 			 "%s: failed with status = %d\n",
3316f1f52e75SDan Williams 			 __func__,
3317f1f52e75SDan Williams 			 status);
3318f1f52e75SDan Williams 
3319f1f52e75SDan Williams 	return status;
3320f1f52e75SDan Williams }
3321f1f52e75SDan Williams 
3322f1f52e75SDan Williams /**
3323f1f52e75SDan Williams  * isci_io_request_build() - This function builds the io request object.
3324d9dcb4baSDan Williams  * @ihost: This parameter specifies the ISCI host object
3325f1f52e75SDan Williams  * @request: This parameter points to the isci_request object allocated in the
3326f1f52e75SDan Williams  *    request construct function.
3327db35a083SLee Jones  * @idev: This parameter is the handle for the sci core's remote device
3328f1f52e75SDan Williams  *    object that is the destination for this request.
3329f1f52e75SDan Williams  *
3330f1f52e75SDan Williams  * SCI_SUCCESS on successfull completion, or specific failure code.
3331f1f52e75SDan Williams  */
isci_io_request_build(struct isci_host * ihost,struct isci_request * request,struct isci_remote_device * idev)3332d9dcb4baSDan Williams static enum sci_status isci_io_request_build(struct isci_host *ihost,
3333f1f52e75SDan Williams 					     struct isci_request *request,
333478a6f06eSDan Williams 					     struct isci_remote_device *idev)
3335f1f52e75SDan Williams {
3336f1f52e75SDan Williams 	enum sci_status status = SCI_SUCCESS;
3337f1f52e75SDan Williams 	struct sas_task *task = isci_request_access_task(request);
3338f1f52e75SDan Williams 
3339d9dcb4baSDan Williams 	dev_dbg(&ihost->pdev->dev,
334078a6f06eSDan Williams 		"%s: idev = 0x%p; request = %p, "
3341f1f52e75SDan Williams 		"num_scatter = %d\n",
3342f1f52e75SDan Williams 		__func__,
334378a6f06eSDan Williams 		idev,
3344f1f52e75SDan Williams 		request,
3345f1f52e75SDan Williams 		task->num_scatter);
3346f1f52e75SDan Williams 
3347f1f52e75SDan Williams 	/* map the sgl addresses, if present.
3348f1f52e75SDan Williams 	 * libata does the mapping for sata devices
3349f1f52e75SDan Williams 	 * before we get the request.
3350f1f52e75SDan Williams 	 */
3351f1f52e75SDan Williams 	if (task->num_scatter &&
3352f1f52e75SDan Williams 	    !sas_protocol_ata(task->task_proto) &&
3353f1f52e75SDan Williams 	    !(SAS_PROTOCOL_SMP & task->task_proto)) {
3354f1f52e75SDan Williams 
3355f1f52e75SDan Williams 		request->num_sg_entries = dma_map_sg(
3356d9dcb4baSDan Williams 			&ihost->pdev->dev,
3357f1f52e75SDan Williams 			task->scatter,
3358f1f52e75SDan Williams 			task->num_scatter,
3359f1f52e75SDan Williams 			task->data_dir
3360f1f52e75SDan Williams 			);
3361f1f52e75SDan Williams 
3362f1f52e75SDan Williams 		if (request->num_sg_entries == 0)
3363f1f52e75SDan Williams 			return SCI_FAILURE_INSUFFICIENT_RESOURCES;
3364f1f52e75SDan Williams 	}
3365f1f52e75SDan Williams 
336689a7301fSDan Williams 	status = sci_io_request_construct(ihost, idev, request);
3367f1f52e75SDan Williams 
3368f1f52e75SDan Williams 	if (status != SCI_SUCCESS) {
3369a8a0a133SDan Williams 		dev_dbg(&ihost->pdev->dev,
3370f1f52e75SDan Williams 			 "%s: failed request construct\n",
3371f1f52e75SDan Williams 			 __func__);
3372f1f52e75SDan Williams 		return SCI_FAILURE;
3373f1f52e75SDan Williams 	}
3374f1f52e75SDan Williams 
3375f1f52e75SDan Williams 	switch (task->task_proto) {
3376f1f52e75SDan Williams 	case SAS_PROTOCOL_SMP:
3377f1f52e75SDan Williams 		status = isci_smp_request_build(request);
3378f1f52e75SDan Williams 		break;
3379f1f52e75SDan Williams 	case SAS_PROTOCOL_SSP:
3380f1f52e75SDan Williams 		status = isci_request_ssp_request_construct(request);
3381f1f52e75SDan Williams 		break;
3382f1f52e75SDan Williams 	case SAS_PROTOCOL_SATA:
3383f1f52e75SDan Williams 	case SAS_PROTOCOL_STP:
3384f1f52e75SDan Williams 	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
3385f1f52e75SDan Williams 		status = isci_request_stp_request_construct(request);
3386f1f52e75SDan Williams 		break;
3387f1f52e75SDan Williams 	default:
3388a8a0a133SDan Williams 		dev_dbg(&ihost->pdev->dev,
3389f1f52e75SDan Williams 			 "%s: unknown protocol\n", __func__);
3390f1f52e75SDan Williams 		return SCI_FAILURE;
3391f1f52e75SDan Williams 	}
3392f1f52e75SDan Williams 
3393*6f827701SSu Hui 	return status;
3394f1f52e75SDan Williams }
3395f1f52e75SDan Williams 
isci_request_from_tag(struct isci_host * ihost,u16 tag)3396db056250SDan Williams static struct isci_request *isci_request_from_tag(struct isci_host *ihost, u16 tag)
3397f1f52e75SDan Williams {
33980d0cf14cSDan Williams 	struct isci_request *ireq;
3399f1f52e75SDan Williams 
3400db056250SDan Williams 	ireq = ihost->reqs[ISCI_TAG_TCI(tag)];
34015076a1a9SDan Williams 	ireq->io_tag = tag;
34020d0cf14cSDan Williams 	ireq->io_request_completion = NULL;
340338d8879bSDan Williams 	ireq->flags = 0;
34040d0cf14cSDan Williams 	ireq->num_sg_entries = 0;
3405f1f52e75SDan Williams 
34060d0cf14cSDan Williams 	return ireq;
3407f1f52e75SDan Williams }
3408f1f52e75SDan Williams 
isci_io_request_from_tag(struct isci_host * ihost,struct sas_task * task,u16 tag)3409c39d5aa4SJohn Garry struct isci_request *isci_io_request_from_tag(struct isci_host *ihost,
3410f1f52e75SDan Williams 					      struct sas_task *task,
3411db056250SDan Williams 					      u16 tag)
3412f1f52e75SDan Williams {
34130d0cf14cSDan Williams 	struct isci_request *ireq;
3414f1f52e75SDan Williams 
3415db056250SDan Williams 	ireq = isci_request_from_tag(ihost, tag);
34160d0cf14cSDan Williams 	ireq->ttype_ptr.io_task_ptr = task;
34173b34c169SJeff Skirvin 	clear_bit(IREQ_TMF, &ireq->flags);
34180d0cf14cSDan Williams 	task->lldd_task = ireq;
3419db056250SDan Williams 
34200d0cf14cSDan Williams 	return ireq;
3421f1f52e75SDan Williams }
3422f1f52e75SDan Williams 
isci_tmf_request_from_tag(struct isci_host * ihost,struct isci_tmf * isci_tmf,u16 tag)3423db056250SDan Williams struct isci_request *isci_tmf_request_from_tag(struct isci_host *ihost,
3424f1f52e75SDan Williams 					       struct isci_tmf *isci_tmf,
3425db056250SDan Williams 					       u16 tag)
3426f1f52e75SDan Williams {
34270d0cf14cSDan Williams 	struct isci_request *ireq;
3428f1f52e75SDan Williams 
3429db056250SDan Williams 	ireq = isci_request_from_tag(ihost, tag);
34300d0cf14cSDan Williams 	ireq->ttype_ptr.tmf_task_ptr = isci_tmf;
34313b34c169SJeff Skirvin 	set_bit(IREQ_TMF, &ireq->flags);
3432db056250SDan Williams 
34330d0cf14cSDan Williams 	return ireq;
3434f1f52e75SDan Williams }
3435f1f52e75SDan Williams 
isci_request_execute(struct isci_host * ihost,struct isci_remote_device * idev,struct sas_task * task,struct isci_request * ireq)3436209fae14SDan Williams int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *idev,
3437c39d5aa4SJohn Garry 			 struct sas_task *task, struct isci_request *ireq)
3438f1f52e75SDan Williams {
3439584d902eSColin Ian King 	enum sci_status status;
3440f1f52e75SDan Williams 	unsigned long flags;
34410d0cf14cSDan Williams 	int ret = 0;
3442f1f52e75SDan Williams 
3443db056250SDan Williams 	status = isci_io_request_build(ihost, ireq, idev);
3444f1f52e75SDan Williams 	if (status != SCI_SUCCESS) {
3445a8a0a133SDan Williams 		dev_dbg(&ihost->pdev->dev,
3446f1f52e75SDan Williams 			 "%s: request_construct failed - status = 0x%x\n",
3447f1f52e75SDan Williams 			 __func__,
3448f1f52e75SDan Williams 			 status);
3449db056250SDan Williams 		return status;
3450f1f52e75SDan Williams 	}
3451f1f52e75SDan Williams 
34520d0cf14cSDan Williams 	spin_lock_irqsave(&ihost->scic_lock, flags);
3453f1f52e75SDan Williams 
34549274f45eSJeff Skirvin 	if (test_bit(IDEV_IO_NCQERROR, &idev->flags)) {
34559274f45eSJeff Skirvin 
34569274f45eSJeff Skirvin 		if (isci_task_is_ncq_recovery(task)) {
34579274f45eSJeff Skirvin 
34589274f45eSJeff Skirvin 			/* The device is in an NCQ recovery state.  Issue the
34599274f45eSJeff Skirvin 			 * request on the task side.  Note that it will
34609274f45eSJeff Skirvin 			 * complete on the I/O request side because the
34619274f45eSJeff Skirvin 			 * request was built that way (ie.
34629274f45eSJeff Skirvin 			 * ireq->is_task_management_request is false).
34639274f45eSJeff Skirvin 			 */
346489a7301fSDan Williams 			status = sci_controller_start_task(ihost,
346578a6f06eSDan Williams 							    idev,
34665076a1a9SDan Williams 							    ireq);
34679274f45eSJeff Skirvin 		} else {
34689274f45eSJeff Skirvin 			status = SCI_FAILURE;
34699274f45eSJeff Skirvin 		}
34709274f45eSJeff Skirvin 	} else {
34719274f45eSJeff Skirvin 		/* send the request, let the core assign the IO TAG.	*/
347289a7301fSDan Williams 		status = sci_controller_start_io(ihost, idev,
34735076a1a9SDan Williams 						  ireq);
34749274f45eSJeff Skirvin 	}
3475312e0c24SDan Williams 
3476f1f52e75SDan Williams 	if (status != SCI_SUCCESS &&
3477f1f52e75SDan Williams 	    status != SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) {
3478a8a0a133SDan Williams 		dev_dbg(&ihost->pdev->dev,
3479f1f52e75SDan Williams 			 "%s: failed request start (0x%x)\n",
3480f1f52e75SDan Williams 			 __func__, status);
34810d0cf14cSDan Williams 		spin_unlock_irqrestore(&ihost->scic_lock, flags);
3482db056250SDan Williams 		return status;
3483f1f52e75SDan Williams 	}
3484f1f52e75SDan Williams 	/* Either I/O started OK, or the core has signaled that
3485f1f52e75SDan Williams 	 * the device needs a target reset.
3486f1f52e75SDan Williams 	 */
348714aaa9f0SJeff Skirvin 	if (status != SCI_SUCCESS) {
3488f1f52e75SDan Williams 		/* The request did not really start in the
3489f1f52e75SDan Williams 		 * hardware, so clear the request handle
3490f1f52e75SDan Williams 		 * here so no terminations will be done.
3491f1f52e75SDan Williams 		 */
349238d8879bSDan Williams 		set_bit(IREQ_TERMINATED, &ireq->flags);
3493f1f52e75SDan Williams 	}
34940d0cf14cSDan Williams 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
3495f1f52e75SDan Williams 
3496f1f52e75SDan Williams 	if (status ==
3497f1f52e75SDan Williams 	    SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) {
3498f1f52e75SDan Williams 		/* Signal libsas that we need the SCSI error
3499f1f52e75SDan Williams 		 * handler thread to work on this I/O and that
3500f1f52e75SDan Williams 		 * we want a device reset.
3501f1f52e75SDan Williams 		 */
3502f1f52e75SDan Williams 		spin_lock_irqsave(&task->task_state_lock, flags);
3503f1f52e75SDan Williams 		task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
3504f1f52e75SDan Williams 		spin_unlock_irqrestore(&task->task_state_lock, flags);
3505f1f52e75SDan Williams 
3506f1f52e75SDan Williams 		/* Cause this task to be scheduled in the SCSI error
3507f1f52e75SDan Williams 		 * handler thread.
3508f1f52e75SDan Williams 		 */
3509312d3e56SDan Williams 		sas_task_abort(task);
3510f1f52e75SDan Williams 
3511f1f52e75SDan Williams 		/* Change the status, since we are holding
3512f1f52e75SDan Williams 		 * the I/O until it is managed by the SCSI
3513f1f52e75SDan Williams 		 * error handler.
3514f1f52e75SDan Williams 		 */
3515f1f52e75SDan Williams 		status = SCI_SUCCESS;
3516f1f52e75SDan Williams 	}
3517f1f52e75SDan Williams 
3518f1f52e75SDan Williams 	return ret;
3519f1f52e75SDan Williams }
3520