From f1f52e75939b56c40b3d153ae99faf2720250242 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 10 May 2011 02:28:45 -0700 Subject: isci: uplevel request infrastructure * Consolidate tiny header files * Move files out of core/ (drop core/scic_sds_ prefix) * Merge core/scic_sds_request.[ch] into request.[ch] * Cleanup request.c namespace (clean forward declarations and global namespace pollution) Reported-by: Christoph Hellwig Signed-off-by: Dan Williams --- drivers/scsi/isci/Makefile | 8 +- drivers/scsi/isci/core/sci_util.c | 86 - drivers/scsi/isci/core/sci_util.h | 97 - drivers/scsi/isci/core/scic_io_request.h | 226 -- drivers/scsi/isci/core/scic_sds_phy.c | 1 - drivers/scsi/isci/core/scic_sds_port.c | 2 +- drivers/scsi/isci/core/scic_sds_request.c | 1523 ---------- drivers/scsi/isci/core/scic_sds_request.h | 491 --- drivers/scsi/isci/core/scic_sds_smp_request.c | 520 ---- drivers/scsi/isci/core/scic_sds_smp_request.h | 67 - drivers/scsi/isci/core/scic_sds_ssp_request.c | 240 -- .../scsi/isci/core/scic_sds_stp_packet_request.h | 113 - drivers/scsi/isci/core/scic_sds_stp_pio_request.h | 104 - drivers/scsi/isci/core/scic_sds_stp_request.c | 1594 ---------- drivers/scsi/isci/core/scic_sds_stp_request.h | 178 -- drivers/scsi/isci/core/scic_task_request.h | 104 - drivers/scsi/isci/host.c | 2 - drivers/scsi/isci/isci.h | 19 + drivers/scsi/isci/port.c | 1 - drivers/scsi/isci/remote_device.c | 3 - drivers/scsi/isci/remote_node_context.c | 1 - drivers/scsi/isci/remote_node_table.c | 1 - drivers/scsi/isci/request.c | 3124 ++++++++++++++------ drivers/scsi/isci/request.h | 442 ++- drivers/scsi/isci/sata.c | 2 - drivers/scsi/isci/smp_request.c | 518 ++++ drivers/scsi/isci/ssp_request.c | 240 ++ drivers/scsi/isci/stp_request.c | 1590 ++++++++++ drivers/scsi/isci/stp_request.h | 195 ++ drivers/scsi/isci/task.c | 3 - drivers/scsi/isci/unsolicited_frame_control.c | 5 +- 31 files changed, 5248 insertions(+), 6252 deletions(-) delete mode 100644 drivers/scsi/isci/core/sci_util.c delete mode 100644 drivers/scsi/isci/core/sci_util.h delete mode 100644 drivers/scsi/isci/core/scic_io_request.h delete mode 100644 drivers/scsi/isci/core/scic_sds_request.c delete mode 100644 drivers/scsi/isci/core/scic_sds_request.h delete mode 100644 drivers/scsi/isci/core/scic_sds_smp_request.c delete mode 100644 drivers/scsi/isci/core/scic_sds_smp_request.h delete mode 100644 drivers/scsi/isci/core/scic_sds_ssp_request.c delete mode 100644 drivers/scsi/isci/core/scic_sds_stp_packet_request.h delete mode 100644 drivers/scsi/isci/core/scic_sds_stp_pio_request.h delete mode 100644 drivers/scsi/isci/core/scic_sds_stp_request.c delete mode 100644 drivers/scsi/isci/core/scic_sds_stp_request.h delete mode 100644 drivers/scsi/isci/core/scic_task_request.h create mode 100644 drivers/scsi/isci/smp_request.c create mode 100644 drivers/scsi/isci/ssp_request.c create mode 100644 drivers/scsi/isci/stp_request.c create mode 100644 drivers/scsi/isci/stp_request.h (limited to 'drivers/scsi') diff --git a/drivers/scsi/isci/Makefile b/drivers/scsi/isci/Makefile index cfc640f9dc3f..a7d1eb33eca2 100644 --- a/drivers/scsi/isci/Makefile +++ b/drivers/scsi/isci/Makefile @@ -7,11 +7,9 @@ isci-objs := init.o phy.o request.o sata.o \ remote_node_context.o \ remote_node_table.o \ unsolicited_frame_control.o \ - core/scic_sds_request.o \ - core/scic_sds_stp_request.o \ + stp_request.o \ + ssp_request.o \ + smp_request.o \ core/scic_sds_port.o \ core/scic_sds_port_configuration_agent.o \ core/scic_sds_phy.o \ - core/scic_sds_ssp_request.o \ - core/scic_sds_smp_request.o \ - core/sci_util.o diff --git a/drivers/scsi/isci/core/sci_util.c b/drivers/scsi/isci/core/sci_util.c deleted file mode 100644 index 595d8da1abba..000000000000 --- a/drivers/scsi/isci/core/sci_util.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "sci_util.h" -#include "request.h" - -void *scic_request_get_virt_addr(struct scic_sds_request *sci_req, dma_addr_t phys_addr) -{ - struct isci_request *ireq = sci_req_to_ireq(sci_req); - dma_addr_t offset; - - BUG_ON(phys_addr < ireq->request_daddr); - - offset = phys_addr - ireq->request_daddr; - - BUG_ON(offset >= sizeof(*ireq)); - - return (char *)ireq + offset; -} - -dma_addr_t scic_io_request_get_dma_addr(struct scic_sds_request *sds_request, - void *virt_addr) -{ - struct isci_request *isci_request = sci_req_to_ireq(sds_request); - - char *requested_addr = (char *)virt_addr; - char *base_addr = (char *)isci_request; - - BUG_ON(requested_addr < base_addr); - BUG_ON((requested_addr - base_addr) >= sizeof(*isci_request)); - - return isci_request->request_daddr + (requested_addr - base_addr); -} diff --git a/drivers/scsi/isci/core/sci_util.h b/drivers/scsi/isci/core/sci_util.h deleted file mode 100644 index 0f9dd0fe1266..000000000000 --- a/drivers/scsi/isci/core/sci_util.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SCI_UTIL_H_ -#define _SCI_UTIL_H_ - -#include "scic_sds_request.h" - -#define SCIC_BUILD_DWORD(char_buffer) \ - (\ - ((char_buffer)[0] << 24) \ - | ((char_buffer)[1] << 16) \ - | ((char_buffer)[2] << 8) \ - | ((char_buffer)[3]) \ - ) - -#define sci_cb_make_physical_address(physical_addr, addr_upper, addr_lower) \ - ((physical_addr) = (addr_lower) | ((u64)addr_upper) << 32) - -/** - * sci_swab32_cpy - convert between scsi and scu-hardware byte format - * @dest: receive the 4-byte endian swapped version of src - * @src: word aligned source buffer - * - * scu hardware handles SSP/SMP control, response, and unidentified - * frames in "big endian dword" order. Regardless of host endian this - * is always a swab32()-per-dword conversion of the standard definition, - * i.e. single byte fields swapped and multi-byte fields in little- - * endian - */ -static inline void sci_swab32_cpy(void *_dest, void *_src, ssize_t word_cnt) -{ - u32 *dest = _dest, *src = _src; - - while (--word_cnt >= 0) - dest[word_cnt] = swab32(src[word_cnt]); -} - -void *scic_request_get_virt_addr(struct scic_sds_request *sds_request, - dma_addr_t phys_addr); - -dma_addr_t scic_io_request_get_dma_addr(struct scic_sds_request *sds_request, - void *virt_addr); - -#endif /* _SCI_UTIL_H_ */ diff --git a/drivers/scsi/isci/core/scic_io_request.h b/drivers/scsi/isci/core/scic_io_request.h deleted file mode 100644 index a4664cc3c576..000000000000 --- a/drivers/scsi/isci/core/scic_io_request.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SCIC_IO_REQUEST_H_ -#define _SCIC_IO_REQUEST_H_ - -#include - -struct scic_sds_request; -struct scic_sds_remote_device; -struct scic_sds_controller; - -/** - * This enumeration specifies the transport protocol utilized for the request. - * - * - */ -typedef enum { - /** - * This enumeration constant indicates that no protocol has yet been - * set. - */ - SCIC_NO_PROTOCOL, - - /** - * This enumeration constant indicates that the protocol utilized - * is the Serial Management Protocol. - */ - SCIC_SMP_PROTOCOL, - - /** - * This enumeration constant indicates that the protocol utilized - * is the Serial SCSI Protocol. - */ - SCIC_SSP_PROTOCOL, - - /** - * This enumeration constant indicates that the protocol utilized - * is the Serial-ATA Tunneling Protocol. - */ - SCIC_STP_PROTOCOL - -} SCIC_TRANSPORT_PROTOCOL; - -enum sci_status scic_io_request_construct( - struct scic_sds_controller *scic_controller, - struct scic_sds_remote_device *scic_remote_device, - u16 io_tag, struct scic_sds_request *sci_req); - -/** - * scic_io_request_construct_basic_ssp() - This method is called by the SCI - * user to build an SSP IO request. - * @scic_io_request: This parameter specifies the handle to the io request - * object to be built. - * - * - The user must have previously called scic_io_request_construct() on the - * supplied IO request. Indicate if the controller successfully built the IO - * request. SCI_SUCCESS This value is returned if the IO request was - * successfully built. SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned - * if the remote_device does not support the SSP protocol. - * SCI_FAILURE_INVALID_ASSOCIATION This value is returned if the user did not - * properly set the association between the SCIC IO request and the user's IO - * request. - */ -enum sci_status scic_io_request_construct_basic_ssp( - struct scic_sds_request *scic_io_request); - - - - - -/** - * scic_io_request_construct_basic_sata() - This method is called by the SCI - * Core user to build an STP IO request. - * @scic_io_request: This parameter specifies the handle to the io request - * object to be built. - * - * - The user must have previously called scic_io_request_construct() on the - * supplied IO request. Indicate if the controller successfully built the IO - * request. SCI_SUCCESS This value is returned if the IO request was - * successfully built. SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned - * if the remote_device does not support the STP protocol. - * SCI_FAILURE_INVALID_ASSOCIATION This value is returned if the user did not - * properly set the association between the SCIC IO request and the user's IO - * request. - */ -enum sci_status scic_io_request_construct_basic_sata( - struct scic_sds_request *scic_io_request); - - - - -/** - * scic_io_request_construct_smp() - This method is called by the SCI user to - * build an SMP IO request. - * @scic_io_request: This parameter specifies the handle to the io request - * object to be built. - * - * - The user must have previously called scic_io_request_construct() on the - * supplied IO request. Indicate if the controller successfully built the IO - * request. SCI_SUCCESS This value is returned if the IO request was - * successfully built. SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned - * if the remote_device does not support the SMP protocol. - * SCI_FAILURE_INVALID_ASSOCIATION This value is returned if the user did not - * properly set the association between the SCIC IO request and the user's IO - * request. - */ -enum sci_status scic_io_request_construct_smp( - struct scic_sds_request *scic_io_request); - - - -/** - * scic_request_get_controller_status() - This method returns the controller - * specific IO/Task request status. These status values are unique to the - * specific controller being managed by the SCIC. - * @io_request: the handle to the IO or task management request object for - * which to retrieve the status. - * - * This method returns a value indicating the controller specific request - * status. - */ -u32 scic_request_get_controller_status( - struct scic_sds_request *io_request); - -/** - * scic_io_request_get_io_tag() - This method will return the IO tag utilized - * by the IO request. - * @scic_io_request: This parameter specifies the handle to the io request - * object for which to return the IO tag. - * - * An unsigned integer representing the IO tag being utilized. - * SCI_CONTROLLER_INVALID_IO_TAG This value is returned if the IO does not - * currently have an IO tag allocated to it. All return other values indicate a - * legitimate tag. - */ -u16 scic_io_request_get_io_tag( - struct scic_sds_request *scic_io_request); - - -/** - * scic_stp_io_request_set_ncq_tag() - This method will assign an NCQ tag to - * the io request object. The caller of this function must make sure that - * only valid NCQ tags are assigned to the io request object. - * @scic_io_request: This parameter specifies the handle to the io request - * object to which to assign the ncq tag. - * @ncq_tag: This parameter specifies the NCQ tag to be utilized for the - * supplied core IO request. It is up to the user to make sure that this is - * a valid NCQ tag. - * - * none This function is only valid for SATA NCQ requests. - */ -void scic_stp_io_request_set_ncq_tag( - struct scic_sds_request *scic_io_request, - u16 ncq_tag); - -/** - * scic_io_request_get_number_of_bytes_transferred() - This method will return - * the number of bytes transferred from the SCU - * @scic_io_request: This parameter specifies the handle to the io request - * whose data length was not eqaul to the data length specified in the - * request. When the driver gets an early io completion status from the - * hardware, this routine should be called to get the actual number of bytes - * transferred - * - * The return is the number of bytes transferred when the data legth is not - * equal to the specified length in the io request - */ -u32 scic_io_request_get_number_of_bytes_transferred( - struct scic_sds_request *scic_io_request); - - -#endif /* _SCIC_IO_REQUEST_H_ */ - diff --git a/drivers/scsi/isci/core/scic_sds_phy.c b/drivers/scsi/isci/core/scic_sds_phy.c index 6b49d94bc9cc..150509b0c69e 100644 --- a/drivers/scsi/isci/core/scic_sds_phy.c +++ b/drivers/scsi/isci/core/scic_sds_phy.c @@ -61,7 +61,6 @@ #include "scic_sds_phy.h" #include "scic_sds_port.h" #include "remote_node_context.h" -#include "sci_util.h" #include "scu_event_codes.h" #include "timers.h" diff --git a/drivers/scsi/isci/core/scic_sds_port.c b/drivers/scsi/isci/core/scic_sds_port.c index 652917eeead4..a9f3ce111b86 100644 --- a/drivers/scsi/isci/core/scic_sds_port.c +++ b/drivers/scsi/isci/core/scic_sds_port.c @@ -60,9 +60,9 @@ #include "scic_sds_port.h" #include "remote_device.h" #include "remote_node_context.h" -#include "scic_sds_request.h" #include "registers.h" #include "timers.h" +#include "scu_task_context.h" #define SCIC_SDS_PORT_MIN_TIMER_COUNT (SCI_MAX_PORTS) #define SCIC_SDS_PORT_MAX_TIMER_COUNT (SCI_MAX_PORTS) diff --git a/drivers/scsi/isci/core/scic_sds_request.c b/drivers/scsi/isci/core/scic_sds_request.c deleted file mode 100644 index cd279601de01..000000000000 --- a/drivers/scsi/isci/core/scic_sds_request.c +++ /dev/null @@ -1,1523 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "scic_io_request.h" -#include "registers.h" -#include "scic_sds_port.h" -#include "remote_device.h" -#include "scic_sds_request.h" -#include "scic_sds_smp_request.h" -#include "scic_sds_stp_request.h" -#include "unsolicited_frame_control.h" -#include "sci_util.h" -#include "scu_completion_codes.h" -#include "scu_task_context.h" -#include "request.h" -#include "task.h" - -/* - * **************************************************************************** - * * SCIC SDS IO REQUEST CONSTANTS - * **************************************************************************** */ - -/** - * - * - * We have no timer requirements for IO requests right now - */ -#define SCIC_SDS_IO_REQUEST_MINIMUM_TIMER_COUNT (0) -#define SCIC_SDS_IO_REQUEST_MAXIMUM_TIMER_COUNT (0) - -/** - * This method returns the sgl element pair for the specificed sgl_pair index. - * @sci_req: This parameter specifies the IO request for which to retrieve - * the Scatter-Gather List element pair. - * @sgl_pair_index: This parameter specifies the index into the SGL element - * pair to be retrieved. - * - * This method returns a pointer to an struct scu_sgl_element_pair. - */ -static struct scu_sgl_element_pair *scic_sds_request_get_sgl_element_pair( - struct scic_sds_request *sci_req, - u32 sgl_pair_index - ) { - struct scu_task_context *task_context; - - task_context = (struct scu_task_context *)sci_req->task_context_buffer; - - if (sgl_pair_index == 0) { - return &task_context->sgl_pair_ab; - } else if (sgl_pair_index == 1) { - return &task_context->sgl_pair_cd; - } - - return &sci_req->sg_table[sgl_pair_index - 2]; -} - -/** - * This function will build the SGL list for an IO request. - * @sci_req: This parameter specifies the IO request for which to build - * the Scatter-Gather List. - * - */ -void scic_sds_request_build_sgl(struct scic_sds_request *sds_request) -{ - struct isci_request *isci_request = sci_req_to_ireq(sds_request); - struct isci_host *isci_host = isci_request->isci_host; - struct sas_task *task = isci_request_access_task(isci_request); - struct scatterlist *sg = NULL; - dma_addr_t dma_addr; - u32 sg_idx = 0; - struct scu_sgl_element_pair *scu_sg = NULL; - struct scu_sgl_element_pair *prev_sg = NULL; - - if (task->num_scatter > 0) { - sg = task->scatter; - - while (sg) { - scu_sg = scic_sds_request_get_sgl_element_pair( - sds_request, - sg_idx); - - SCU_SGL_COPY(scu_sg->A, sg); - - sg = sg_next(sg); - - if (sg) { - SCU_SGL_COPY(scu_sg->B, sg); - sg = sg_next(sg); - } else - SCU_SGL_ZERO(scu_sg->B); - - if (prev_sg) { - dma_addr = - scic_io_request_get_dma_addr( - sds_request, - scu_sg); - - prev_sg->next_pair_upper = - upper_32_bits(dma_addr); - prev_sg->next_pair_lower = - lower_32_bits(dma_addr); - } - - prev_sg = scu_sg; - sg_idx++; - } - } else { /* handle when no sg */ - scu_sg = scic_sds_request_get_sgl_element_pair(sds_request, - sg_idx); - - dma_addr = dma_map_single(&isci_host->pdev->dev, - task->scatter, - task->total_xfer_len, - task->data_dir); - - isci_request->zero_scatter_daddr = dma_addr; - - scu_sg->A.length = task->total_xfer_len; - scu_sg->A.address_upper = upper_32_bits(dma_addr); - scu_sg->A.address_lower = lower_32_bits(dma_addr); - } - - if (scu_sg) { - scu_sg->next_pair_upper = 0; - scu_sg->next_pair_lower = 0; - } -} - -static void scic_sds_ssp_io_request_assign_buffers(struct scic_sds_request *sci_req) -{ - if (sci_req->was_tag_assigned_by_user == false) - sci_req->task_context_buffer = &sci_req->tc; -} - -static void scic_sds_io_request_build_ssp_command_iu(struct scic_sds_request *sci_req) -{ - struct ssp_cmd_iu *cmd_iu; - struct isci_request *ireq = sci_req_to_ireq(sci_req); - struct sas_task *task = isci_request_access_task(ireq); - - cmd_iu = &sci_req->ssp.cmd; - - memcpy(cmd_iu->LUN, task->ssp_task.LUN, 8); - cmd_iu->add_cdb_len = 0; - cmd_iu->_r_a = 0; - cmd_iu->_r_b = 0; - cmd_iu->en_fburst = 0; /* unsupported */ - cmd_iu->task_prio = task->ssp_task.task_prio; - cmd_iu->task_attr = task->ssp_task.task_attr; - cmd_iu->_r_c = 0; - - sci_swab32_cpy(&cmd_iu->cdb, task->ssp_task.cdb, - sizeof(task->ssp_task.cdb) / sizeof(u32)); -} - -static void scic_sds_task_request_build_ssp_task_iu(struct scic_sds_request *sci_req) -{ - struct ssp_task_iu *task_iu; - struct isci_request *ireq = sci_req_to_ireq(sci_req); - struct sas_task *task = isci_request_access_task(ireq); - struct isci_tmf *isci_tmf = isci_request_access_tmf(ireq); - - task_iu = &sci_req->ssp.tmf; - - memset(task_iu, 0, sizeof(struct ssp_task_iu)); - - memcpy(task_iu->LUN, task->ssp_task.LUN, 8); - - task_iu->task_func = isci_tmf->tmf_code; - task_iu->task_tag = - (ireq->ttype == tmf_task) ? - isci_tmf->io_tag : - SCI_CONTROLLER_INVALID_IO_TAG; -} - -/** - * This method is will fill in the SCU Task Context for any type of SSP request. - * @sci_req: - * @task_context: - * - */ -static void scu_ssp_reqeust_construct_task_context( - struct scic_sds_request *sds_request, - struct scu_task_context *task_context) -{ - dma_addr_t dma_addr; - struct scic_sds_controller *controller; - struct scic_sds_remote_device *target_device; - struct scic_sds_port *target_port; - - controller = scic_sds_request_get_controller(sds_request); - target_device = scic_sds_request_get_device(sds_request); - target_port = scic_sds_request_get_port(sds_request); - - /* Fill in the TC with the its required data */ - task_context->abort = 0; - task_context->priority = 0; - task_context->initiator_request = 1; - task_context->connection_rate = target_device->connection_rate; - task_context->protocol_engine_index = - scic_sds_controller_get_protocol_engine_group(controller); - task_context->logical_port_index = - scic_sds_port_get_index(target_port); - task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP; - task_context->valid = SCU_TASK_CONTEXT_VALID; - task_context->context_type = SCU_TASK_CONTEXT_TYPE; - - task_context->remote_node_index = - scic_sds_remote_device_get_index(sds_request->target_device); - task_context->command_code = 0; - - task_context->link_layer_control = 0; - task_context->do_not_dma_ssp_good_response = 1; - task_context->strict_ordering = 0; - task_context->control_frame = 0; - task_context->timeout_enable = 0; - task_context->block_guard_enable = 0; - - task_context->address_modifier = 0; - - /* task_context->type.ssp.tag = sci_req->io_tag; */ - task_context->task_phase = 0x01; - - if (sds_request->was_tag_assigned_by_user) { - /* - * Build the task context now since we have already read - * the data - */ - sds_request->post_context = - (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | - (scic_sds_controller_get_protocol_engine_group( - controller) << - SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | - (scic_sds_port_get_index(target_port) << - SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) | - scic_sds_io_tag_get_index(sds_request->io_tag)); - } else { - /* - * Build the task context now since we have already read - * the data - * - * I/O tag index is not assigned because we have to wait - * until we get a TCi - */ - sds_request->post_context = - (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | - (scic_sds_controller_get_protocol_engine_group( - owning_controller) << - SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | - (scic_sds_port_get_index(target_port) << - SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)); - } - - /* - * Copy the physical address for the command buffer to the - * SCU Task Context - */ - dma_addr = scic_io_request_get_dma_addr(sds_request, - &sds_request->ssp.cmd); - - task_context->command_iu_upper = upper_32_bits(dma_addr); - task_context->command_iu_lower = lower_32_bits(dma_addr); - - /* - * Copy the physical address for the response buffer to the - * SCU Task Context - */ - dma_addr = scic_io_request_get_dma_addr(sds_request, - &sds_request->ssp.rsp); - - task_context->response_iu_upper = upper_32_bits(dma_addr); - task_context->response_iu_lower = lower_32_bits(dma_addr); -} - -/** - * This method is will fill in the SCU Task Context for a SSP IO request. - * @sci_req: - * - */ -static void scu_ssp_io_request_construct_task_context( - struct scic_sds_request *sci_req, - enum dma_data_direction dir, - u32 len) -{ - struct scu_task_context *task_context; - - task_context = scic_sds_request_get_task_context(sci_req); - - scu_ssp_reqeust_construct_task_context(sci_req, task_context); - - task_context->ssp_command_iu_length = - sizeof(struct ssp_cmd_iu) / sizeof(u32); - task_context->type.ssp.frame_type = SSP_COMMAND; - - switch (dir) { - case DMA_FROM_DEVICE: - case DMA_NONE: - default: - task_context->task_type = SCU_TASK_TYPE_IOREAD; - break; - case DMA_TO_DEVICE: - task_context->task_type = SCU_TASK_TYPE_IOWRITE; - break; - } - - task_context->transfer_length_bytes = len; - - if (task_context->transfer_length_bytes > 0) - scic_sds_request_build_sgl(sci_req); -} - -static void scic_sds_ssp_task_request_assign_buffers(struct scic_sds_request *sci_req) -{ - if (sci_req->was_tag_assigned_by_user == false) - sci_req->task_context_buffer = &sci_req->tc; -} - -/** - * This method will fill in the SCU Task Context for a SSP Task request. The - * following important settings are utilized: -# priority == - * SCU_TASK_PRIORITY_HIGH. This ensures that the task request is issued - * ahead of other task destined for the same Remote Node. -# task_type == - * SCU_TASK_TYPE_IOREAD. This simply indicates that a normal request type - * (i.e. non-raw frame) is being utilized to perform task management. -# - * control_frame == 1. This ensures that the proper endianess is set so - * that the bytes are transmitted in the right order for a task frame. - * @sci_req: This parameter specifies the task request object being - * constructed. - * - */ -static void scu_ssp_task_request_construct_task_context( - struct scic_sds_request *sci_req) -{ - struct scu_task_context *task_context; - - task_context = scic_sds_request_get_task_context(sci_req); - - scu_ssp_reqeust_construct_task_context(sci_req, task_context); - - task_context->control_frame = 1; - task_context->priority = SCU_TASK_PRIORITY_HIGH; - task_context->task_type = SCU_TASK_TYPE_RAW_FRAME; - task_context->transfer_length_bytes = 0; - task_context->type.ssp.frame_type = SSP_TASK; - task_context->ssp_command_iu_length = - sizeof(struct ssp_task_iu) / sizeof(u32); -} - - -/** - * This method constructs the SSP Command IU data for this ssp passthrough - * comand request object. - * @sci_req: This parameter specifies the request object for which the SSP - * command information unit is being built. - * - * enum sci_status, returns invalid parameter is cdb > 16 - */ - - -/** - * This method constructs the SATA request object. - * @sci_req: - * @sat_protocol: - * @transfer_length: - * @data_direction: - * @copy_rx_frame: - * - * enum sci_status - */ -static enum sci_status -scic_io_request_construct_sata(struct scic_sds_request *sci_req, - u32 len, - enum dma_data_direction dir, - bool copy) -{ - enum sci_status status = SCI_SUCCESS; - struct isci_request *ireq = sci_req_to_ireq(sci_req); - struct sas_task *task = isci_request_access_task(ireq); - - /* check for management protocols */ - if (ireq->ttype == tmf_task) { - struct isci_tmf *tmf = isci_request_access_tmf(ireq); - - if (tmf->tmf_code == isci_tmf_sata_srst_high || - tmf->tmf_code == isci_tmf_sata_srst_low) - return scic_sds_stp_soft_reset_request_construct(sci_req); - else { - dev_err(scic_to_dev(sci_req->owning_controller), - "%s: Request 0x%p received un-handled SAT " - "management protocol 0x%x.\n", - __func__, sci_req, tmf->tmf_code); - - return SCI_FAILURE; - } - } - - if (!sas_protocol_ata(task->task_proto)) { - dev_err(scic_to_dev(sci_req->owning_controller), - "%s: Non-ATA protocol in SATA path: 0x%x\n", - __func__, - task->task_proto); - return SCI_FAILURE; - - } - - /* non data */ - if (task->data_dir == DMA_NONE) - return scic_sds_stp_non_data_request_construct(sci_req); - - /* NCQ */ - if (task->ata_task.use_ncq) - return scic_sds_stp_ncq_request_construct(sci_req, len, dir); - - /* DMA */ - if (task->ata_task.dma_xfer) - return scic_sds_stp_udma_request_construct(sci_req, len, dir); - else /* PIO */ - return scic_sds_stp_pio_request_construct(sci_req, copy); - - return status; -} - -enum sci_status scic_io_request_construct_basic_ssp( - struct scic_sds_request *sci_req) -{ - struct isci_request *ireq = sci_req_to_ireq(sci_req); - struct sas_task *task = isci_request_access_task(ireq); - - sci_req->protocol = SCIC_SSP_PROTOCOL; - - scu_ssp_io_request_construct_task_context(sci_req, - task->data_dir, - task->total_xfer_len); - - scic_sds_io_request_build_ssp_command_iu(sci_req); - - sci_base_state_machine_change_state( - &sci_req->state_machine, - SCI_BASE_REQUEST_STATE_CONSTRUCTED); - - return SCI_SUCCESS; -} - - -enum sci_status scic_task_request_construct_ssp( - struct scic_sds_request *sci_req) -{ - /* Construct the SSP Task SCU Task Context */ - scu_ssp_task_request_construct_task_context(sci_req); - - /* Fill in the SSP Task IU */ - scic_sds_task_request_build_ssp_task_iu(sci_req); - - sci_base_state_machine_change_state(&sci_req->state_machine, - SCI_BASE_REQUEST_STATE_CONSTRUCTED); - - return SCI_SUCCESS; -} - - -enum sci_status scic_io_request_construct_basic_sata( - struct scic_sds_request *sci_req) -{ - enum sci_status status; - struct scic_sds_stp_request *stp_req; - bool copy = false; - struct isci_request *isci_request = sci_req_to_ireq(sci_req); - struct sas_task *task = isci_request_access_task(isci_request); - - stp_req = &sci_req->stp.req; - sci_req->protocol = SCIC_STP_PROTOCOL; - - copy = (task->data_dir == DMA_NONE) ? false : true; - - status = scic_io_request_construct_sata(sci_req, - task->total_xfer_len, - task->data_dir, - copy); - - if (status == SCI_SUCCESS) - sci_base_state_machine_change_state(&sci_req->state_machine, - SCI_BASE_REQUEST_STATE_CONSTRUCTED); - - return status; -} - - -enum sci_status scic_task_request_construct_sata(struct scic_sds_request *sci_req) -{ - enum sci_status status = SCI_SUCCESS; - struct isci_request *ireq = sci_req_to_ireq(sci_req); - - /* check for management protocols */ - if (ireq->ttype == tmf_task) { - struct isci_tmf *tmf = isci_request_access_tmf(ireq); - - if (tmf->tmf_code == isci_tmf_sata_srst_high || - tmf->tmf_code == isci_tmf_sata_srst_low) { - status = scic_sds_stp_soft_reset_request_construct(sci_req); - } else { - dev_err(scic_to_dev(sci_req->owning_controller), - "%s: Request 0x%p received un-handled SAT " - "Protocol 0x%x.\n", - __func__, sci_req, tmf->tmf_code); - - return SCI_FAILURE; - } - } - - if (status == SCI_SUCCESS) - sci_base_state_machine_change_state( - &sci_req->state_machine, - SCI_BASE_REQUEST_STATE_CONSTRUCTED); - - return status; -} - - -u16 scic_io_request_get_io_tag( - struct scic_sds_request *sci_req) -{ - return sci_req->io_tag; -} - - -u32 scic_request_get_controller_status( - struct scic_sds_request *sci_req) -{ - return sci_req->scu_status; -} - -#define SCU_TASK_CONTEXT_SRAM 0x200000 -u32 scic_io_request_get_number_of_bytes_transferred( - struct scic_sds_request *scic_sds_request) -{ - struct scic_sds_controller *scic = scic_sds_request->owning_controller; - u32 ret_val = 0; - - if (readl(&scic->smu_registers->address_modifier) == 0) { - void __iomem *scu_reg_base = scic->scu_registers; - /* - * get the bytes of data from the Address == BAR1 + 20002Ch + (256*TCi) where - * BAR1 is the scu_registers - * 0x20002C = 0x200000 + 0x2c - * = start of task context SRAM + offset of (type.ssp.data_offset) - * TCi is the io_tag of struct scic_sds_request */ - ret_val = readl(scu_reg_base + - (SCU_TASK_CONTEXT_SRAM + offsetof(struct scu_task_context, type.ssp.data_offset)) + - ((sizeof(struct scu_task_context)) * scic_sds_io_tag_get_index(scic_sds_request->io_tag))); - } - - return ret_val; -} - - -/* - * **************************************************************************** - * * SCIC SDS Interface Implementation - * **************************************************************************** */ - -enum sci_status -scic_sds_request_start(struct scic_sds_request *request) -{ - if (request->device_sequence != - scic_sds_remote_device_get_sequence(request->target_device)) - return SCI_FAILURE; - - if (request->state_handlers->start_handler) - return request->state_handlers->start_handler(request); - - dev_warn(scic_to_dev(request->owning_controller), - "%s: SCIC IO Request requested to start while in wrong " - "state %d\n", - __func__, - sci_base_state_machine_get_state(&request->state_machine)); - - return SCI_FAILURE_INVALID_STATE; -} - -enum sci_status -scic_sds_io_request_terminate(struct scic_sds_request *request) -{ - if (request->state_handlers->abort_handler) - return request->state_handlers->abort_handler(request); - - dev_warn(scic_to_dev(request->owning_controller), - "%s: SCIC IO Request requested to abort while in wrong " - "state %d\n", - __func__, - sci_base_state_machine_get_state(&request->state_machine)); - - return SCI_FAILURE_INVALID_STATE; -} - -enum sci_status -scic_sds_io_request_complete(struct scic_sds_request *request) -{ - if (request->state_handlers->complete_handler) - return request->state_handlers->complete_handler(request); - - dev_warn(scic_to_dev(request->owning_controller), - "%s: SCIC IO Request requested to complete while in wrong " - "state %d\n", - __func__, - sci_base_state_machine_get_state(&request->state_machine)); - - return SCI_FAILURE_INVALID_STATE; -} - -enum sci_status scic_sds_io_request_event_handler( - struct scic_sds_request *request, - u32 event_code) -{ - if (request->state_handlers->event_handler) - return request->state_handlers->event_handler(request, event_code); - - dev_warn(scic_to_dev(request->owning_controller), - "%s: SCIC IO Request given event code notification %x while " - "in wrong state %d\n", - __func__, - event_code, - sci_base_state_machine_get_state(&request->state_machine)); - - return SCI_FAILURE_INVALID_STATE; -} - -enum sci_status -scic_sds_io_request_tc_completion(struct scic_sds_request *request, u32 completion_code) -{ - if (request->state_machine.current_state_id == SCI_BASE_REQUEST_STATE_STARTED && - request->has_started_substate_machine == false) - return scic_sds_request_started_state_tc_completion_handler(request, completion_code); - else if (request->state_handlers->tc_completion_handler) - return request->state_handlers->tc_completion_handler(request, completion_code); - - dev_warn(scic_to_dev(request->owning_controller), - "%s: SCIC IO Request given task completion notification %x " - "while in wrong state %d\n", - __func__, - completion_code, - sci_base_state_machine_get_state(&request->state_machine)); - - return SCI_FAILURE_INVALID_STATE; - -} - - -/** - * - * @sci_req: The SCIC_SDS_IO_REQUEST_T object for which the start - * operation is to be executed. - * @frame_index: The frame index returned by the hardware for the reqeust - * object. - * - * This method invokes the core state frame handler for the - * SCIC_SDS_IO_REQUEST_T object. enum sci_status - */ -enum sci_status scic_sds_io_request_frame_handler( - struct scic_sds_request *request, - u32 frame_index) -{ - if (request->state_handlers->frame_handler) - return request->state_handlers->frame_handler(request, frame_index); - - dev_warn(scic_to_dev(request->owning_controller), - "%s: SCIC IO Request given unexpected frame %x while in " - "state %d\n", - __func__, - frame_index, - sci_base_state_machine_get_state(&request->state_machine)); - - scic_sds_controller_release_frame(request->owning_controller, frame_index); - return SCI_FAILURE_INVALID_STATE; -} - -/* - * This function copies response data for requests returning response data - * instead of sense data. - * @sci_req: This parameter specifies the request object for which to copy - * the response data. - */ -void scic_sds_io_request_copy_response(struct scic_sds_request *sci_req) -{ - void *resp_buf; - u32 len; - struct ssp_response_iu *ssp_response; - struct isci_request *ireq = sci_req_to_ireq(sci_req); - struct isci_tmf *isci_tmf = isci_request_access_tmf(ireq); - - ssp_response = &sci_req->ssp.rsp; - - resp_buf = &isci_tmf->resp.resp_iu; - - len = min_t(u32, - SSP_RESP_IU_MAX_SIZE, - be32_to_cpu(ssp_response->response_data_len)); - - memcpy(resp_buf, ssp_response->resp_data, len); -} - -/* - * ***************************************************************************** - * * CONSTRUCTED STATE HANDLERS - * ***************************************************************************** */ - -/* - * This method implements the action taken when a constructed - * SCIC_SDS_IO_REQUEST_T object receives a scic_sds_request_start() request. - * This method will, if necessary, allocate a TCi for the io request object and - * then will, if necessary, copy the constructed TC data into the actual TC - * buffer. If everything is successful the post context field is updated with - * the TCi so the controller can post the request to the hardware. enum sci_status - * SCI_SUCCESS SCI_FAILURE_INSUFFICIENT_RESOURCES - */ -static enum sci_status scic_sds_request_constructed_state_start_handler( - struct scic_sds_request *request) -{ - struct scu_task_context *task_context; - - if (request->io_tag == SCI_CONTROLLER_INVALID_IO_TAG) { - request->io_tag = - scic_controller_allocate_io_tag(request->owning_controller); - } - - /* Record the IO Tag in the request */ - if (request->io_tag != SCI_CONTROLLER_INVALID_IO_TAG) { - task_context = request->task_context_buffer; - - task_context->task_index = scic_sds_io_tag_get_index(request->io_tag); - - switch (task_context->protocol_type) { - case SCU_TASK_CONTEXT_PROTOCOL_SMP: - case SCU_TASK_CONTEXT_PROTOCOL_SSP: - /* SSP/SMP Frame */ - task_context->type.ssp.tag = request->io_tag; - task_context->type.ssp.target_port_transfer_tag = 0xFFFF; - break; - - case SCU_TASK_CONTEXT_PROTOCOL_STP: - /* - * STP/SATA Frame - * task_context->type.stp.ncq_tag = request->ncq_tag; */ - break; - - case SCU_TASK_CONTEXT_PROTOCOL_NONE: - /* / @todo When do we set no protocol type? */ - break; - - default: - /* This should never happen since we build the IO requests */ - break; - } - - /* - * Check to see if we need to copy the task context buffer - * or have been building into the task context buffer */ - if (request->was_tag_assigned_by_user == false) { - scic_sds_controller_copy_task_context( - request->owning_controller, request); - } - - /* Add to the post_context the io tag value */ - request->post_context |= scic_sds_io_tag_get_index(request->io_tag); - - /* Everything is good go ahead and change state */ - sci_base_state_machine_change_state(&request->state_machine, - SCI_BASE_REQUEST_STATE_STARTED); - - return SCI_SUCCESS; - } - - return SCI_FAILURE_INSUFFICIENT_RESOURCES; -} - -/* - * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T - * object receives a scic_sds_request_terminate() request. Since the request - * has not yet been posted to the hardware the request transitions to the - * completed state. enum sci_status SCI_SUCCESS - */ -static enum sci_status scic_sds_request_constructed_state_abort_handler( - struct scic_sds_request *request) -{ - /* - * This request has been terminated by the user make sure that the correct - * status code is returned */ - scic_sds_request_set_status(request, - SCU_TASK_DONE_TASK_ABORT, - SCI_FAILURE_IO_TERMINATED); - - sci_base_state_machine_change_state(&request->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - return SCI_SUCCESS; -} - -/* - * ***************************************************************************** - * * STARTED STATE HANDLERS - * ***************************************************************************** */ - -/* - * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T - * object receives a scic_sds_request_terminate() request. Since the request - * has been posted to the hardware the io request state is changed to the - * aborting state. enum sci_status SCI_SUCCESS - */ -enum sci_status scic_sds_request_started_state_abort_handler( - struct scic_sds_request *request) -{ - if (request->has_started_substate_machine) - sci_base_state_machine_stop(&request->started_substate_machine); - - sci_base_state_machine_change_state(&request->state_machine, - SCI_BASE_REQUEST_STATE_ABORTING); - return SCI_SUCCESS; -} - -/* - * scic_sds_request_started_state_tc_completion_handler() - This method process - * TC (task context) completions for normal IO request (i.e. Task/Abort - * Completions of type 0). This method will update the - * SCIC_SDS_IO_REQUEST_T::status field. - * @sci_req: This parameter specifies the request for which a completion - * occurred. - * @completion_code: This parameter specifies the completion code received from - * the SCU. - * - */ -enum sci_status -scic_sds_request_started_state_tc_completion_handler( - struct scic_sds_request *sci_req, - u32 completion_code) -{ - u8 datapres; - struct ssp_response_iu *resp_iu; - - /* - * TODO: Any SDMA return code of other than 0 is bad - * decode 0x003C0000 to determine SDMA status - */ - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - scic_sds_request_set_status(sci_req, - SCU_TASK_DONE_GOOD, - SCI_SUCCESS); - break; - - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_EARLY_RESP): - { - /* - * There are times when the SCU hardware will return an early - * response because the io request specified more data than is - * returned by the target device (mode pages, inquiry data, - * etc.). We must check the response stats to see if this is - * truly a failed request or a good request that just got - * completed early. - */ - struct ssp_response_iu *resp = &sci_req->ssp.rsp; - ssize_t word_cnt = SSP_RESP_IU_MAX_SIZE / sizeof(u32); - - sci_swab32_cpy(&sci_req->ssp.rsp, - &sci_req->ssp.rsp, - word_cnt); - - if (resp->status == 0) { - scic_sds_request_set_status( - sci_req, - SCU_TASK_DONE_GOOD, - SCI_SUCCESS_IO_DONE_EARLY); - } else { - scic_sds_request_set_status( - sci_req, - SCU_TASK_DONE_CHECK_RESPONSE, - SCI_FAILURE_IO_RESPONSE_VALID); - } - } - break; - - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CHECK_RESPONSE): - { - ssize_t word_cnt = SSP_RESP_IU_MAX_SIZE / sizeof(u32); - - sci_swab32_cpy(&sci_req->ssp.rsp, - &sci_req->ssp.rsp, - word_cnt); - - scic_sds_request_set_status(sci_req, - SCU_TASK_DONE_CHECK_RESPONSE, - SCI_FAILURE_IO_RESPONSE_VALID); - break; - } - - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_RESP_LEN_ERR): - /* - * / @todo With TASK_DONE_RESP_LEN_ERR is the response frame - * guaranteed to be received before this completion status is - * posted? - */ - resp_iu = &sci_req->ssp.rsp; - datapres = resp_iu->datapres; - - if ((datapres == 0x01) || (datapres == 0x02)) { - scic_sds_request_set_status( - sci_req, - SCU_TASK_DONE_CHECK_RESPONSE, - SCI_FAILURE_IO_RESPONSE_VALID); - } else - scic_sds_request_set_status( - sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS); - break; - - /* only stp device gets suspended. */ - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_ACK_NAK_TO): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_PERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_NAK_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_DATA_LEN_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_ABORT_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_XR_WD_LEN): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_MAX_PLD_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_RESP): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_SDBFIS): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDB_ERR): - if (sci_req->protocol == SCIC_STP_PROTOCOL) { - scic_sds_request_set_status( - sci_req, - SCU_GET_COMPLETION_TL_STATUS(completion_code) >> - SCU_COMPLETION_TL_STATUS_SHIFT, - SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED); - } else { - scic_sds_request_set_status( - sci_req, - SCU_GET_COMPLETION_TL_STATUS(completion_code) >> - SCU_COMPLETION_TL_STATUS_SHIFT, - SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR); - } - break; - - /* both stp/ssp device gets suspended */ - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LF_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_WRONG_DESTINATION): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_BAD_DESTINATION): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_ZONE_VIOLATION): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED): - scic_sds_request_set_status( - sci_req, - SCU_GET_COMPLETION_TL_STATUS(completion_code) >> - SCU_COMPLETION_TL_STATUS_SHIFT, - SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED); - break; - - /* neither ssp nor stp gets suspended. */ - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_NAK_CMD_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_XR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_XR_IU_LEN_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDMA_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_OFFSET_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_EXCESS_DATA): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_DATA): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_OPEN_FAIL): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_VIIT_ENTRY_NV): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_IIT_ENTRY_NV): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_RNCNV_OUTBOUND): - default: - scic_sds_request_set_status( - sci_req, - SCU_GET_COMPLETION_TL_STATUS(completion_code) >> - SCU_COMPLETION_TL_STATUS_SHIFT, - SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR); - break; - } - - /* - * TODO: This is probably wrong for ACK/NAK timeout conditions - */ - - /* In all cases we will treat this as the completion of the IO req. */ - sci_base_state_machine_change_state( - &sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - return SCI_SUCCESS; -} - -/* - * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T - * object receives a scic_sds_request_frame_handler() request. This method - * first determines the frame type received. If this is a response frame then - * the response data is copied to the io request response buffer for processing - * at completion time. If the frame type is not a response buffer an error is - * logged. enum sci_status SCI_SUCCESS SCI_FAILURE_INVALID_PARAMETER_VALUE - */ -static enum sci_status -scic_sds_request_started_state_frame_handler(struct scic_sds_request *sci_req, - u32 frame_index) -{ - enum sci_status status; - u32 *frame_header; - struct ssp_frame_hdr ssp_hdr; - ssize_t word_cnt; - - status = scic_sds_unsolicited_frame_control_get_header( - &(scic_sds_request_get_controller(sci_req)->uf_control), - frame_index, - (void **)&frame_header); - - word_cnt = sizeof(struct ssp_frame_hdr) / sizeof(u32); - sci_swab32_cpy(&ssp_hdr, frame_header, word_cnt); - - if (ssp_hdr.frame_type == SSP_RESPONSE) { - struct ssp_response_iu *resp_iu; - ssize_t word_cnt = SSP_RESP_IU_MAX_SIZE / sizeof(u32); - - status = scic_sds_unsolicited_frame_control_get_buffer( - &(scic_sds_request_get_controller(sci_req)->uf_control), - frame_index, - (void **)&resp_iu); - - sci_swab32_cpy(&sci_req->ssp.rsp, - resp_iu, word_cnt); - - resp_iu = &sci_req->ssp.rsp; - - if ((resp_iu->datapres == 0x01) || - (resp_iu->datapres == 0x02)) { - scic_sds_request_set_status( - sci_req, - SCU_TASK_DONE_CHECK_RESPONSE, - SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR); - } else - scic_sds_request_set_status( - sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS); - } else { - /* This was not a response frame why did it get forwarded? */ - dev_err(scic_to_dev(sci_req->owning_controller), - "%s: SCIC IO Request 0x%p received unexpected " - "frame %d type 0x%02x\n", - __func__, - sci_req, - frame_index, - ssp_hdr.frame_type); - } - - /* - * In any case we are done with this frame buffer return it to the - * controller - */ - scic_sds_controller_release_frame( - sci_req->owning_controller, frame_index); - - return SCI_SUCCESS; -} - -/* - * ***************************************************************************** - * * COMPLETED STATE HANDLERS - * ***************************************************************************** */ - - -/* - * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T - * object receives a scic_sds_request_complete() request. This method frees up - * any io request resources that have been allocated and transitions the - * request to its final state. Consider stopping the state machine instead of - * transitioning to the final state? enum sci_status SCI_SUCCESS - */ -static enum sci_status scic_sds_request_completed_state_complete_handler( - struct scic_sds_request *request) -{ - if (request->was_tag_assigned_by_user != true) { - scic_controller_free_io_tag( - request->owning_controller, request->io_tag); - } - - if (request->saved_rx_frame_index != SCU_INVALID_FRAME_INDEX) { - scic_sds_controller_release_frame( - request->owning_controller, request->saved_rx_frame_index); - } - - sci_base_state_machine_change_state(&request->state_machine, - SCI_BASE_REQUEST_STATE_FINAL); - return SCI_SUCCESS; -} - -/* - * ***************************************************************************** - * * ABORTING STATE HANDLERS - * ***************************************************************************** */ - -/* - * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T - * object receives a scic_sds_request_terminate() request. This method is the - * io request aborting state abort handlers. On receipt of a multiple - * terminate requests the io request will transition to the completed state. - * This should not happen in normal operation. enum sci_status SCI_SUCCESS - */ -static enum sci_status scic_sds_request_aborting_state_abort_handler( - struct scic_sds_request *request) -{ - sci_base_state_machine_change_state(&request->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - return SCI_SUCCESS; -} - -/* - * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T - * object receives a scic_sds_request_task_completion() request. This method - * decodes the completion type waiting for the abort task complete - * notification. When the abort task complete is received the io request - * transitions to the completed state. enum sci_status SCI_SUCCESS - */ -static enum sci_status scic_sds_request_aborting_state_tc_completion_handler( - struct scic_sds_request *sci_req, - u32 completion_code) -{ - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case (SCU_TASK_DONE_GOOD << SCU_COMPLETION_TL_STATUS_SHIFT): - case (SCU_TASK_DONE_TASK_ABORT << SCU_COMPLETION_TL_STATUS_SHIFT): - scic_sds_request_set_status( - sci_req, SCU_TASK_DONE_TASK_ABORT, SCI_FAILURE_IO_TERMINATED - ); - - sci_base_state_machine_change_state(&sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - break; - - default: - /* - * Unless we get some strange error wait for the task abort to complete - * TODO: Should there be a state change for this completion? */ - break; - } - - return SCI_SUCCESS; -} - -/* - * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T - * object receives a scic_sds_request_frame_handler() request. This method - * discards the unsolicited frame since we are waiting for the abort task - * completion. enum sci_status SCI_SUCCESS - */ -static enum sci_status scic_sds_request_aborting_state_frame_handler( - struct scic_sds_request *sci_req, - u32 frame_index) -{ - /* TODO: Is it even possible to get an unsolicited frame in the aborting state? */ - - scic_sds_controller_release_frame( - sci_req->owning_controller, frame_index); - - return SCI_SUCCESS; -} - -static const struct scic_sds_io_request_state_handler scic_sds_request_state_handler_table[] = { - [SCI_BASE_REQUEST_STATE_INITIAL] = { - }, - [SCI_BASE_REQUEST_STATE_CONSTRUCTED] = { - .start_handler = scic_sds_request_constructed_state_start_handler, - .abort_handler = scic_sds_request_constructed_state_abort_handler, - }, - [SCI_BASE_REQUEST_STATE_STARTED] = { - .abort_handler = scic_sds_request_started_state_abort_handler, - .tc_completion_handler = scic_sds_request_started_state_tc_completion_handler, - .frame_handler = scic_sds_request_started_state_frame_handler, - }, - [SCI_BASE_REQUEST_STATE_COMPLETED] = { - .complete_handler = scic_sds_request_completed_state_complete_handler, - }, - [SCI_BASE_REQUEST_STATE_ABORTING] = { - .abort_handler = scic_sds_request_aborting_state_abort_handler, - .tc_completion_handler = scic_sds_request_aborting_state_tc_completion_handler, - .frame_handler = scic_sds_request_aborting_state_frame_handler, - }, - [SCI_BASE_REQUEST_STATE_FINAL] = { - }, -}; - -/** - * scic_sds_request_initial_state_enter() - - * @object: This parameter specifies the base object for which the state - * transition is occurring. - * - * This method implements the actions taken when entering the - * SCI_BASE_REQUEST_STATE_INITIAL state. This state is entered when the initial - * base request is constructed. Entry into the initial state sets all handlers - * for the io request object to their default handlers. none - */ -static void scic_sds_request_initial_state_enter(void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_request_state_handler_table, - SCI_BASE_REQUEST_STATE_INITIAL - ); -} - -/** - * scic_sds_request_constructed_state_enter() - - * @object: The io request object that is to enter the constructed state. - * - * This method implements the actions taken when entering the - * SCI_BASE_REQUEST_STATE_CONSTRUCTED state. The method sets the state handlers - * for the the constructed state. none - */ -static void scic_sds_request_constructed_state_enter(void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_request_state_handler_table, - SCI_BASE_REQUEST_STATE_CONSTRUCTED - ); -} - -/** - * scic_sds_request_started_state_enter() - - * @object: This parameter specifies the base object for which the state - * transition is occurring. This is cast into a SCIC_SDS_IO_REQUEST object. - * - * This method implements the actions taken when entering the - * SCI_BASE_REQUEST_STATE_STARTED state. If the io request object type is a - * SCSI Task request we must enter the started substate machine. none - */ -static void scic_sds_request_started_state_enter(void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_request_state_handler_table, - SCI_BASE_REQUEST_STATE_STARTED - ); - - /* - * Most of the request state machines have a started substate machine so - * start its execution on the entry to the started state. */ - if (sci_req->has_started_substate_machine == true) - sci_base_state_machine_start(&sci_req->started_substate_machine); -} - -/** - * scic_sds_request_started_state_exit() - - * @object: This parameter specifies the base object for which the state - * transition is occurring. This object is cast into a SCIC_SDS_IO_REQUEST - * object. - * - * This method implements the actions taken when exiting the - * SCI_BASE_REQUEST_STATE_STARTED state. For task requests the action will be - * to stop the started substate machine. none - */ -static void scic_sds_request_started_state_exit(void *object) -{ - struct scic_sds_request *sci_req = object; - - if (sci_req->has_started_substate_machine == true) - sci_base_state_machine_stop(&sci_req->started_substate_machine); -} - -/** - * scic_sds_request_completed_state_enter() - - * @object: This parameter specifies the base object for which the state - * transition is occurring. This object is cast into a SCIC_SDS_IO_REQUEST - * object. - * - * This method implements the actions taken when entering the - * SCI_BASE_REQUEST_STATE_COMPLETED state. This state is entered when the - * SCIC_SDS_IO_REQUEST has completed. The method will decode the request - * completion status and convert it to an enum sci_status to return in the - * completion callback function. none - */ -static void scic_sds_request_completed_state_enter(void *object) -{ - struct scic_sds_request *sci_req = object; - struct scic_sds_controller *scic = - scic_sds_request_get_controller(sci_req); - struct isci_host *ihost = scic_to_ihost(scic); - struct isci_request *ireq = sci_req_to_ireq(sci_req); - - SET_STATE_HANDLER(sci_req, - scic_sds_request_state_handler_table, - SCI_BASE_REQUEST_STATE_COMPLETED); - - /* Tell the SCI_USER that the IO request is complete */ - if (sci_req->is_task_management_request == false) - isci_request_io_request_complete(ihost, - ireq, - sci_req->sci_status); - else - isci_task_request_complete(ihost, ireq, sci_req->sci_status); -} - -/** - * scic_sds_request_aborting_state_enter() - - * @object: This parameter specifies the base object for which the state - * transition is occurring. This object is cast into a SCIC_SDS_IO_REQUEST - * object. - * - * This method implements the actions taken when entering the - * SCI_BASE_REQUEST_STATE_ABORTING state. none - */ -static void scic_sds_request_aborting_state_enter(void *object) -{ - struct scic_sds_request *sci_req = object; - - /* Setting the abort bit in the Task Context is required by the silicon. */ - sci_req->task_context_buffer->abort = 1; - - SET_STATE_HANDLER( - sci_req, - scic_sds_request_state_handler_table, - SCI_BASE_REQUEST_STATE_ABORTING - ); -} - -/** - * scic_sds_request_final_state_enter() - - * @object: This parameter specifies the base object for which the state - * transition is occurring. This is cast into a SCIC_SDS_IO_REQUEST object. - * - * This method implements the actions taken when entering the - * SCI_BASE_REQUEST_STATE_FINAL state. The only action required is to put the - * state handlers in place. none - */ -static void scic_sds_request_final_state_enter(void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_request_state_handler_table, - SCI_BASE_REQUEST_STATE_FINAL - ); -} - -static const struct sci_base_state scic_sds_request_state_table[] = { - [SCI_BASE_REQUEST_STATE_INITIAL] = { - .enter_state = scic_sds_request_initial_state_enter, - }, - [SCI_BASE_REQUEST_STATE_CONSTRUCTED] = { - .enter_state = scic_sds_request_constructed_state_enter, - }, - [SCI_BASE_REQUEST_STATE_STARTED] = { - .enter_state = scic_sds_request_started_state_enter, - .exit_state = scic_sds_request_started_state_exit - }, - [SCI_BASE_REQUEST_STATE_COMPLETED] = { - .enter_state = scic_sds_request_completed_state_enter, - }, - [SCI_BASE_REQUEST_STATE_ABORTING] = { - .enter_state = scic_sds_request_aborting_state_enter, - }, - [SCI_BASE_REQUEST_STATE_FINAL] = { - .enter_state = scic_sds_request_final_state_enter, - }, -}; - -static void scic_sds_general_request_construct(struct scic_sds_controller *scic, - struct scic_sds_remote_device *sci_dev, - u16 io_tag, struct scic_sds_request *sci_req) -{ - sci_base_state_machine_construct(&sci_req->state_machine, sci_req, - scic_sds_request_state_table, SCI_BASE_REQUEST_STATE_INITIAL); - sci_base_state_machine_start(&sci_req->state_machine); - - sci_req->io_tag = io_tag; - sci_req->owning_controller = scic; - sci_req->target_device = sci_dev; - sci_req->has_started_substate_machine = false; - sci_req->protocol = SCIC_NO_PROTOCOL; - sci_req->saved_rx_frame_index = SCU_INVALID_FRAME_INDEX; - sci_req->device_sequence = scic_sds_remote_device_get_sequence(sci_dev); - - sci_req->sci_status = SCI_SUCCESS; - sci_req->scu_status = 0; - sci_req->post_context = 0xFFFFFFFF; - - sci_req->is_task_management_request = false; - - if (io_tag == SCI_CONTROLLER_INVALID_IO_TAG) { - sci_req->was_tag_assigned_by_user = false; - sci_req->task_context_buffer = NULL; - } else { - sci_req->was_tag_assigned_by_user = true; - - sci_req->task_context_buffer = - scic_sds_controller_get_task_context_buffer(scic, io_tag); - } -} - -enum sci_status -scic_io_request_construct(struct scic_sds_controller *scic, - struct scic_sds_remote_device *sci_dev, - u16 io_tag, struct scic_sds_request *sci_req) -{ - struct domain_device *dev = sci_dev_to_domain(sci_dev); - enum sci_status status = SCI_SUCCESS; - - /* Build the common part of the request */ - scic_sds_general_request_construct(scic, sci_dev, io_tag, sci_req); - - if (sci_dev->rnc.remote_node_index == - SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) - return SCI_FAILURE_INVALID_REMOTE_DEVICE; - - if (dev->dev_type == SAS_END_DEV) - scic_sds_ssp_io_request_assign_buffers(sci_req); - else if ((dev->dev_type == SATA_DEV) || - (dev->tproto & SAS_PROTOCOL_STP)) { - scic_sds_stp_request_assign_buffers(sci_req); - memset(&sci_req->stp.cmd, 0, sizeof(sci_req->stp.cmd)); - } else if (dev_is_expander(dev)) { - scic_sds_smp_request_assign_buffers(sci_req); - memset(&sci_req->smp.cmd, 0, sizeof(sci_req->smp.cmd)); - } else - status = SCI_FAILURE_UNSUPPORTED_PROTOCOL; - - if (status == SCI_SUCCESS) { - memset(sci_req->task_context_buffer, 0, - offsetof(struct scu_task_context, sgl_pair_ab)); - } - - return status; -} - -enum sci_status scic_task_request_construct(struct scic_sds_controller *scic, - struct scic_sds_remote_device *sci_dev, - u16 io_tag, struct scic_sds_request *sci_req) -{ - struct domain_device *dev = sci_dev_to_domain(sci_dev); - enum sci_status status = SCI_SUCCESS; - - /* Build the common part of the request */ - scic_sds_general_request_construct(scic, sci_dev, io_tag, sci_req); - - if (dev->dev_type == SAS_END_DEV) { - scic_sds_ssp_task_request_assign_buffers(sci_req); - - sci_req->has_started_substate_machine = true; - - /* Construct the started sub-state machine. */ - sci_base_state_machine_construct( - &sci_req->started_substate_machine, - sci_req, - scic_sds_io_request_started_task_mgmt_substate_table, - SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION - ); - } else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) - scic_sds_stp_request_assign_buffers(sci_req); - else - status = SCI_FAILURE_UNSUPPORTED_PROTOCOL; - - if (status == SCI_SUCCESS) { - sci_req->is_task_management_request = true; - memset(sci_req->task_context_buffer, 0, sizeof(struct scu_task_context)); - } - - return status; -} diff --git a/drivers/scsi/isci/core/scic_sds_request.h b/drivers/scsi/isci/core/scic_sds_request.h deleted file mode 100644 index a8d74a15a86b..000000000000 --- a/drivers/scsi/isci/core/scic_sds_request.h +++ /dev/null @@ -1,491 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SCIC_SDS_IO_REQUEST_H_ -#define _SCIC_SDS_IO_REQUEST_H_ - -#include "isci.h" -#include "scic_io_request.h" -#include "state_machine.h" -#include "scu_task_context.h" -#include "scic_sds_stp_request.h" -#include "sas.h" - -struct scic_sds_controller; -struct scic_sds_remote_device; -struct scic_sds_io_request_state_handler; - -/** - * enum _scic_sds_io_request_started_task_mgmt_substates - This enumeration - * depicts all of the substates for a task management request to be - * performed in the STARTED super-state. - * - * - */ -enum scic_sds_raw_request_started_task_mgmt_substates { - /** - * The AWAIT_TC_COMPLETION sub-state indicates that the started raw - * task management request is waiting for the transmission of the - * initial frame (i.e. command, task, etc.). - */ - SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION, - - /** - * This sub-state indicates that the started task management request - * is waiting for the reception of an unsolicited frame - * (i.e. response IU). - */ - SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE, -}; - - -/** - * enum _scic_sds_smp_request_started_substates - This enumeration depicts all - * of the substates for a SMP request to be performed in the STARTED - * super-state. - * - * - */ -enum scic_sds_smp_request_started_substates { - /** - * This sub-state indicates that the started task management request - * is waiting for the reception of an unsolicited frame - * (i.e. response IU). - */ - SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE, - - /** - * The AWAIT_TC_COMPLETION sub-state indicates that the started SMP request is - * waiting for the transmission of the initial frame (i.e. command, task, etc.). - */ - SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION, -}; - -struct scic_sds_request { - /** - * This field contains the information for the base request state machine. - */ - struct sci_base_state_machine state_machine; - - /** - * This field simply points to the controller to which this IO request - * is associated. - */ - struct scic_sds_controller *owning_controller; - - /** - * This field simply points to the remote device to which this IO request - * is associated. - */ - struct scic_sds_remote_device *target_device; - - /** - * This field is utilized to determine if the SCI user is managing - * the IO tag for this request or if the core is managing it. - */ - bool was_tag_assigned_by_user; - - /** - * This field indicates the IO tag for this request. The IO tag is - * comprised of the task_index and a sequence count. The sequence count - * is utilized to help identify tasks from one life to another. - */ - u16 io_tag; - - /** - * This field specifies the protocol being utilized for this - * IO request. - */ - SCIC_TRANSPORT_PROTOCOL protocol; - - /** - * This field indicates the completion status taken from the SCUs - * completion code. It indicates the completion result for the SCU hardware. - */ - u32 scu_status; - - /** - * This field indicates the completion status returned to the SCI user. It - * indicates the users view of the io request completion. - */ - u32 sci_status; - - /** - * This field contains the value to be utilized when posting (e.g. Post_TC, - * Post_TC_Abort) this request to the silicon. - */ - u32 post_context; - - struct scu_task_context *task_context_buffer; - struct scu_task_context tc ____cacheline_aligned; - - /* could be larger with sg chaining */ - #define SCU_SGL_SIZE ((SCU_IO_REQUEST_SGE_COUNT + 1) / 2) - struct scu_sgl_element_pair sg_table[SCU_SGL_SIZE] __attribute__ ((aligned(32))); - - /** - * This field indicates if this request is a task management request or - * normal IO request. - */ - bool is_task_management_request; - - /** - * This field indicates that this request contains an initialized started - * substate machine. - */ - bool has_started_substate_machine; - - /** - * This field is a pointer to the stored rx frame data. It is used in STP - * internal requests and SMP response frames. If this field is non-NULL the - * saved frame must be released on IO request completion. - * - * @todo In the future do we want to keep a list of RX frame buffers? - */ - u32 saved_rx_frame_index; - - /** - * This field specifies the data necessary to manage the sub-state - * machine executed while in the SCI_BASE_REQUEST_STATE_STARTED state. - */ - struct sci_base_state_machine started_substate_machine; - - /** - * This field specifies the current state handlers in place for this - * IO Request object. This field is updated each time the request - * changes state. - */ - const struct scic_sds_io_request_state_handler *state_handlers; - - /** - * This field in the recorded device sequence for the io request. This is - * recorded during the build operation and is compared in the start - * operation. If the sequence is different then there was a change of - * devices from the build to start operations. - */ - u8 device_sequence; - - union { - struct { - union { - struct ssp_cmd_iu cmd; - struct ssp_task_iu tmf; - }; - union { - struct ssp_response_iu rsp; - u8 rsp_buf[SSP_RESP_IU_MAX_SIZE]; - }; - } ssp; - - struct { - struct smp_req cmd; - struct smp_resp rsp; - } smp; - - struct { - struct scic_sds_stp_request req; - struct host_to_dev_fis cmd; - struct dev_to_host_fis rsp; - } stp; - }; - -}; - -static inline struct scic_sds_request *to_sci_req(struct scic_sds_stp_request *stp_req) -{ - struct scic_sds_request *sci_req; - - sci_req = container_of(stp_req, typeof(*sci_req), stp.req); - return sci_req; -} - -/** - * enum sci_base_request_states - This enumeration depicts all the states for - * the common request state machine. - * - * - */ -enum sci_base_request_states { - /** - * Simply the initial state for the base request state machine. - */ - SCI_BASE_REQUEST_STATE_INITIAL, - - /** - * This state indicates that the request has been constructed. This state - * is entered from the INITIAL state. - */ - SCI_BASE_REQUEST_STATE_CONSTRUCTED, - - /** - * This state indicates that the request has been started. This state is - * entered from the CONSTRUCTED state. - */ - SCI_BASE_REQUEST_STATE_STARTED, - - /** - * This state indicates that the request has completed. - * This state is entered from the STARTED state. This state is entered from - * the ABORTING state. - */ - SCI_BASE_REQUEST_STATE_COMPLETED, - - /** - * This state indicates that the request is in the process of being - * terminated/aborted. - * This state is entered from the CONSTRUCTED state. - * This state is entered from the STARTED state. - */ - SCI_BASE_REQUEST_STATE_ABORTING, - - /** - * Simply the final state for the base request state machine. - */ - SCI_BASE_REQUEST_STATE_FINAL, -}; - -typedef enum sci_status (*scic_sds_io_request_handler_t) - (struct scic_sds_request *request); -typedef enum sci_status (*scic_sds_io_request_frame_handler_t) - (struct scic_sds_request *req, u32 frame); -typedef enum sci_status (*scic_sds_io_request_event_handler_t) - (struct scic_sds_request *req, u32 event); -typedef enum sci_status (*scic_sds_io_request_task_completion_handler_t) - (struct scic_sds_request *req, u32 completion_code); - -/** - * struct scic_sds_io_request_state_handler - This is the SDS core definition - * of the state handlers. - * - * - */ -struct scic_sds_io_request_state_handler { - /** - * The start_handler specifies the method invoked when a user attempts to - * start a request. - */ - scic_sds_io_request_handler_t start_handler; - - /** - * The abort_handler specifies the method invoked when a user attempts to - * abort a request. - */ - scic_sds_io_request_handler_t abort_handler; - - /** - * The complete_handler specifies the method invoked when a user attempts to - * complete a request. - */ - scic_sds_io_request_handler_t complete_handler; - - scic_sds_io_request_task_completion_handler_t tc_completion_handler; - scic_sds_io_request_event_handler_t event_handler; - scic_sds_io_request_frame_handler_t frame_handler; - -}; - -extern const struct sci_base_state scic_sds_io_request_started_task_mgmt_substate_table[]; - -/** - * scic_sds_request_get_controller() - - * - * This macro will return the controller for this io request object - */ -#define scic_sds_request_get_controller(sci_req) \ - ((sci_req)->owning_controller) - -/** - * scic_sds_request_get_device() - - * - * This macro will return the device for this io request object - */ -#define scic_sds_request_get_device(sci_req) \ - ((sci_req)->target_device) - -/** - * scic_sds_request_get_port() - - * - * This macro will return the port for this io request object - */ -#define scic_sds_request_get_port(sci_req) \ - scic_sds_remote_device_get_port(scic_sds_request_get_device(sci_req)) - -/** - * scic_sds_request_get_post_context() - - * - * This macro returns the constructed post context result for the io request. - */ -#define scic_sds_request_get_post_context(sci_req) \ - ((sci_req)->post_context) - -/** - * scic_sds_request_get_task_context() - - * - * This is a helper macro to return the os handle for this request object. - */ -#define scic_sds_request_get_task_context(request) \ - ((request)->task_context_buffer) - -/** - * scic_sds_request_set_status() - - * - * This macro will set the scu hardware status and sci request completion - * status for an io request. - */ -#define scic_sds_request_set_status(request, scu_status_code, sci_status_code) \ - { \ - (request)->scu_status = (scu_status_code); \ - (request)->sci_status = (sci_status_code); \ - } - -#define scic_sds_request_complete(a_request) \ - ((a_request)->state_handlers->complete_handler(a_request)) - - -extern enum sci_status -scic_sds_io_request_tc_completion(struct scic_sds_request *request, u32 completion_code); - -/** - * SCU_SGL_ZERO() - - * - * This macro zeros the hardware SGL element data - */ -#define SCU_SGL_ZERO(scu_sge) \ - { \ - (scu_sge).length = 0; \ - (scu_sge).address_lower = 0; \ - (scu_sge).address_upper = 0; \ - (scu_sge).address_modifier = 0; \ - } - -/** - * SCU_SGL_COPY() - - * - * This macro copys the SGL Element data from the host os to the hardware SGL - * elment data - */ -#define SCU_SGL_COPY(scu_sge, os_sge) \ - { \ - (scu_sge).length = sg_dma_len(sg); \ - (scu_sge).address_upper = \ - upper_32_bits(sg_dma_address(sg)); \ - (scu_sge).address_lower = \ - lower_32_bits(sg_dma_address(sg)); \ - (scu_sge).address_modifier = 0; \ - } - -/** - * scic_sds_request_get_user_request() - - * - * This is a helper macro to return the os handle for this request object. - */ -#define scic_sds_request_get_user_request(request) \ - ((request)->user_request) - -/* - * ***************************************************************************** - * * CORE REQUEST PROTOTYPES - * ***************************************************************************** */ - -void scic_sds_request_build_sgl( - struct scic_sds_request *sci_req); - - - -void scic_sds_stp_request_assign_buffers( - struct scic_sds_request *sci_req); - -void scic_sds_smp_request_assign_buffers( - struct scic_sds_request *sci_req); - -/* --------------------------------------------------------------------------- */ - -enum sci_status scic_sds_request_start( - struct scic_sds_request *sci_req); - -enum sci_status scic_sds_io_request_terminate( - struct scic_sds_request *sci_req); - -enum sci_status scic_sds_io_request_complete( - struct scic_sds_request *sci_req); - -void scic_sds_io_request_copy_response( - struct scic_sds_request *sci_req); - -enum sci_status scic_sds_io_request_event_handler( - struct scic_sds_request *sci_req, - u32 event_code); - -enum sci_status scic_sds_io_request_frame_handler( - struct scic_sds_request *sci_req, - u32 frame_index); - - -enum sci_status scic_sds_task_request_terminate( - struct scic_sds_request *sci_req); - -/* - * ***************************************************************************** - * * STARTED STATE HANDLERS - * ***************************************************************************** */ - -enum sci_status scic_sds_request_started_state_abort_handler( - struct scic_sds_request *sci_req); - -enum sci_status scic_sds_request_started_state_tc_completion_handler( - struct scic_sds_request *sci_req, - u32 completion_code); - -#endif /* _SCIC_SDS_IO_REQUEST_H_ */ diff --git a/drivers/scsi/isci/core/scic_sds_smp_request.c b/drivers/scsi/isci/core/scic_sds_smp_request.c deleted file mode 100644 index 6a2b65b9cf0f..000000000000 --- a/drivers/scsi/isci/core/scic_sds_smp_request.c +++ /dev/null @@ -1,520 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "state_machine.h" -#include "remote_device.h" -#include "scic_sds_request.h" -#include "scic_sds_smp_request.h" -#include "sci_util.h" -#include "scu_completion_codes.h" -#include "scu_task_context.h" -#include "host.h" - -static void scu_smp_request_construct_task_context( - struct scic_sds_request *sci_req, - struct smp_req *smp_req); - -void scic_sds_smp_request_assign_buffers(struct scic_sds_request *sci_req) -{ - if (sci_req->was_tag_assigned_by_user == false) - sci_req->task_context_buffer = &sci_req->tc; -} - -/* - * This function will fill in the SCU Task Context for a SMP request. The - * following important settings are utilized: -# task_type == - * SCU_TASK_TYPE_SMP. This simply indicates that a normal request type - * (i.e. non-raw frame) is being utilized to perform task management. -# - * control_frame == 1. This ensures that the proper endianess is set so - * that the bytes are transmitted in the right order for a smp request frame. - * @sci_req: This parameter specifies the smp request object being - * constructed. - * - */ -static void -scu_smp_request_construct_task_context(struct scic_sds_request *sci_req, - struct smp_req *smp_req) -{ - dma_addr_t dma_addr; - struct scic_sds_controller *scic; - struct scic_sds_remote_device *sci_dev; - struct scic_sds_port *sci_port; - struct scu_task_context *task_context; - ssize_t word_cnt = sizeof(struct smp_req) / sizeof(u32); - - /* byte swap the smp request. */ - sci_swab32_cpy(&sci_req->smp.cmd, smp_req, - word_cnt); - - task_context = scic_sds_request_get_task_context(sci_req); - - scic = scic_sds_request_get_controller(sci_req); - sci_dev = scic_sds_request_get_device(sci_req); - sci_port = scic_sds_request_get_port(sci_req); - - /* - * Fill in the TC with the its required data - * 00h - */ - task_context->priority = 0; - task_context->initiator_request = 1; - task_context->connection_rate = sci_dev->connection_rate; - task_context->protocol_engine_index = - scic_sds_controller_get_protocol_engine_group(scic); - task_context->logical_port_index = scic_sds_port_get_index(sci_port); - task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SMP; - task_context->abort = 0; - task_context->valid = SCU_TASK_CONTEXT_VALID; - task_context->context_type = SCU_TASK_CONTEXT_TYPE; - - /* 04h */ - task_context->remote_node_index = sci_dev->rnc.remote_node_index; - task_context->command_code = 0; - task_context->task_type = SCU_TASK_TYPE_SMP_REQUEST; - - /* 08h */ - task_context->link_layer_control = 0; - task_context->do_not_dma_ssp_good_response = 1; - task_context->strict_ordering = 0; - task_context->control_frame = 1; - task_context->timeout_enable = 0; - task_context->block_guard_enable = 0; - - /* 0ch */ - task_context->address_modifier = 0; - - /* 10h */ - task_context->ssp_command_iu_length = smp_req->req_len; - - /* 14h */ - task_context->transfer_length_bytes = 0; - - /* - * 18h ~ 30h, protocol specific - * since commandIU has been build by framework at this point, we just - * copy the frist DWord from command IU to this location. */ - memcpy(&task_context->type.smp, &sci_req->smp.cmd, sizeof(u32)); - - /* - * 40h - * "For SMP you could program it to zero. We would prefer that way - * so that done code will be consistent." - Venki - */ - task_context->task_phase = 0; - - if (sci_req->was_tag_assigned_by_user) { - /* - * Build the task context now since we have already read - * the data - */ - sci_req->post_context = - (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | - (scic_sds_controller_get_protocol_engine_group(scic) << - SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | - (scic_sds_port_get_index(sci_port) << - SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) | - scic_sds_io_tag_get_index(sci_req->io_tag)); - } else { - /* - * Build the task context now since we have already read - * the data. - * I/O tag index is not assigned because we have to wait - * until we get a TCi. - */ - sci_req->post_context = - (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | - (scic_sds_controller_get_protocol_engine_group(scic) << - SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | - (scic_sds_port_get_index(sci_port) << - SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)); - } - - /* - * Copy the physical address for the command buffer to the SCU Task - * Context command buffer should not contain command header. - */ - dma_addr = scic_io_request_get_dma_addr(sci_req, - ((char *) &sci_req->smp.cmd) + - sizeof(u32)); - - task_context->command_iu_upper = upper_32_bits(dma_addr); - task_context->command_iu_lower = lower_32_bits(dma_addr); - - /* SMP response comes as UF, so no need to set response IU address. */ - task_context->response_iu_upper = 0; - task_context->response_iu_lower = 0; -} - -/* - * This function processes an unsolicited frame while the SMP request is waiting - * for a response frame. It will copy the response data, release the - * unsolicited frame, and transition the request to the - * SCI_BASE_REQUEST_STATE_COMPLETED state. - * @sci_req: This parameter specifies the request for which the - * unsolicited frame was received. - * @frame_index: This parameter indicates the unsolicited frame index that - * should contain the response. - * - * This function returns an indication of whether the response frame was handled - * successfully or not. SCI_SUCCESS Currently this value is always returned and - * indicates successful processing of the TC response. - */ -static enum sci_status -scic_sds_smp_request_await_response_frame_handler(struct scic_sds_request *sci_req, - u32 frame_index) -{ - enum sci_status status; - void *frame_header; - struct smp_resp *rsp_hdr = &sci_req->smp.rsp; - ssize_t word_cnt = SMP_RESP_HDR_SZ / sizeof(u32); - - status = scic_sds_unsolicited_frame_control_get_header( - &(scic_sds_request_get_controller(sci_req)->uf_control), - frame_index, - &frame_header); - - /* byte swap the header. */ - sci_swab32_cpy(rsp_hdr, frame_header, word_cnt); - - if (rsp_hdr->frame_type == SMP_RESPONSE) { - void *smp_resp; - - status = scic_sds_unsolicited_frame_control_get_buffer( - &(scic_sds_request_get_controller(sci_req)->uf_control), - frame_index, - &smp_resp); - - word_cnt = (sizeof(struct smp_req) - SMP_RESP_HDR_SZ) / - sizeof(u32); - - sci_swab32_cpy(((u8 *) rsp_hdr) + SMP_RESP_HDR_SZ, - smp_resp, word_cnt); - - scic_sds_request_set_status( - sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS); - - sci_base_state_machine_change_state( - &sci_req->started_substate_machine, - SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION); - } else { - /* This was not a response frame why did it get forwarded? */ - dev_err(scic_to_dev(sci_req->owning_controller), - "%s: SCIC SMP Request 0x%p received unexpected frame " - "%d type 0x%02x\n", - __func__, - sci_req, - frame_index, - rsp_hdr->frame_type); - - scic_sds_request_set_status( - sci_req, - SCU_TASK_DONE_SMP_FRM_TYPE_ERR, - SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR); - - sci_base_state_machine_change_state( - &sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - } - - scic_sds_controller_release_frame(sci_req->owning_controller, - frame_index); - - return SCI_SUCCESS; -} - - -/** - * This method processes an abnormal TC completion while the SMP request is - * waiting for a response frame. It decides what happened to the IO based - * on TC completion status. - * @sci_req: This parameter specifies the request for which the TC - * completion was received. - * @completion_code: This parameter indicates the completion status information - * for the TC. - * - * Indicate if the tc completion handler was successful. SCI_SUCCESS currently - * this method always returns success. - */ -static enum sci_status scic_sds_smp_request_await_response_tc_completion_handler( - struct scic_sds_request *sci_req, - u32 completion_code) -{ - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - /* - * In the AWAIT RESPONSE state, any TC completion is unexpected. - * but if the TC has success status, we complete the IO anyway. */ - scic_sds_request_set_status( - sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS - ); - - sci_base_state_machine_change_state( - &sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - break; - - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR): - /* - * These status has been seen in a specific LSI expander, which sometimes - * is not able to send smp response within 2 ms. This causes our hardware - * break the connection and set TC completion with one of these SMP_XXX_XX_ERR - * status. For these type of error, we ask scic user to retry the request. */ - scic_sds_request_set_status( - sci_req, SCU_TASK_DONE_SMP_RESP_TO_ERR, SCI_FAILURE_RETRY_REQUIRED - ); - - sci_base_state_machine_change_state( - &sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - break; - - default: - /* - * All other completion status cause the IO to be complete. If a NAK - * was received, then it is up to the user to retry the request. */ - scic_sds_request_set_status( - sci_req, - SCU_NORMALIZE_COMPLETION_STATUS(completion_code), - SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR - ); - - sci_base_state_machine_change_state( - &sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - break; - } - - return SCI_SUCCESS; -} - - -/** - * This method processes the completions transport layer (TL) status to - * determine if the SMP request was sent successfully. If the SMP request - * was sent successfully, then the state for the SMP request transits to - * waiting for a response frame. - * @sci_req: This parameter specifies the request for which the TC - * completion was received. - * @completion_code: This parameter indicates the completion status information - * for the TC. - * - * Indicate if the tc completion handler was successful. SCI_SUCCESS currently - * this method always returns success. - */ -static enum sci_status scic_sds_smp_request_await_tc_completion_tc_completion_handler( - struct scic_sds_request *sci_req, - u32 completion_code) -{ - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - scic_sds_request_set_status( - sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS - ); - - sci_base_state_machine_change_state( - &sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - break; - - default: - /* - * All other completion status cause the IO to be complete. If a NAK - * was received, then it is up to the user to retry the request. */ - scic_sds_request_set_status( - sci_req, - SCU_NORMALIZE_COMPLETION_STATUS(completion_code), - SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR - ); - - sci_base_state_machine_change_state( - &sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - break; - } - - return SCI_SUCCESS; -} - - -static const struct scic_sds_io_request_state_handler scic_sds_smp_request_started_substate_handler_table[] = { - [SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE] = { - .abort_handler = scic_sds_request_started_state_abort_handler, - .tc_completion_handler = scic_sds_smp_request_await_response_tc_completion_handler, - .frame_handler = scic_sds_smp_request_await_response_frame_handler, - }, - [SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION] = { - .abort_handler = scic_sds_request_started_state_abort_handler, - .tc_completion_handler = scic_sds_smp_request_await_tc_completion_tc_completion_handler, - } -}; - -/** - * This method performs the actions required when entering the - * SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_RESPONSE sub-state. This - * includes setting the IO request state handlers for this sub-state. - * @object: This parameter specifies the request object for which the sub-state - * change is occurring. - * - * none. - */ -static void scic_sds_smp_request_started_await_response_substate_enter( - void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_smp_request_started_substate_handler_table, - SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE - ); -} - -/** - * This method performs the actions required when entering the - * SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION sub-state. - * This includes setting the SMP request state handlers for this sub-state. - * @object: This parameter specifies the request object for which the sub-state - * change is occurring. - * - * none. - */ -static void scic_sds_smp_request_started_await_tc_completion_substate_enter( - void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_smp_request_started_substate_handler_table, - SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION - ); -} - -static const struct sci_base_state scic_sds_smp_request_started_substate_table[] = { - [SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE] = { - .enter_state = scic_sds_smp_request_started_await_response_substate_enter, - }, - [SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION] = { - .enter_state = scic_sds_smp_request_started_await_tc_completion_substate_enter, - }, -}; - -/** - * This method is called by the SCI user to build an SMP IO request. - * - * - The user must have previously called scic_io_request_construct() on the - * supplied IO request. Indicate if the controller successfully built the IO - * request. SCI_SUCCESS This value is returned if the IO request was - * successfully built. SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned - * if the remote_device does not support the SMP protocol. - * SCI_FAILURE_INVALID_ASSOCIATION This value is returned if the user did not - * properly set the association between the SCIC IO request and the user's IO - * request. - */ -enum sci_status scic_io_request_construct_smp(struct scic_sds_request *sci_req) -{ - struct smp_req *smp_req = kmalloc(sizeof(*smp_req), GFP_KERNEL); - - if (!smp_req) - return SCI_FAILURE_INSUFFICIENT_RESOURCES; - - sci_req->protocol = SCIC_SMP_PROTOCOL; - sci_req->has_started_substate_machine = true; - - /* Construct the started sub-state machine. */ - sci_base_state_machine_construct( - &sci_req->started_substate_machine, - sci_req, - scic_sds_smp_request_started_substate_table, - SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE - ); - - /* Construct the SMP SCU Task Context */ - memcpy(smp_req, &sci_req->smp.cmd, sizeof(*smp_req)); - - /* - * Look at the SMP requests' header fields; for certain SAS 1.x SMP - * functions under SAS 2.0, a zero request length really indicates - * a non-zero default length. */ - if (smp_req->req_len == 0) { - switch (smp_req->func) { - case SMP_DISCOVER: - case SMP_REPORT_PHY_ERR_LOG: - case SMP_REPORT_PHY_SATA: - case SMP_REPORT_ROUTE_INFO: - smp_req->req_len = 2; - break; - case SMP_CONF_ROUTE_INFO: - case SMP_PHY_CONTROL: - case SMP_PHY_TEST_FUNCTION: - smp_req->req_len = 9; - break; - /* Default - zero is a valid default for 2.0. */ - } - } - - scu_smp_request_construct_task_context(sci_req, smp_req); - - sci_base_state_machine_change_state(&sci_req->state_machine, - SCI_BASE_REQUEST_STATE_CONSTRUCTED); - - kfree(smp_req); - - return SCI_SUCCESS; -} diff --git a/drivers/scsi/isci/core/scic_sds_smp_request.h b/drivers/scsi/isci/core/scic_sds_smp_request.h deleted file mode 100644 index f432b7a182cd..000000000000 --- a/drivers/scsi/isci/core/scic_sds_smp_request.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef _SCIC_SDS_SMP_REQUEST_T_ -#define _SCIC_SDS_SMP_REQUEST_T_ - -#include "scic_sds_request.h" - - -u32 scic_sds_smp_request_get_object_size(void); - - -void scic_sds_smp_request_copy_response(struct scic_sds_request *sci_req); - -#endif /* _SCIC_SDS_SMP_REQUEST_T_ */ - diff --git a/drivers/scsi/isci/core/scic_sds_ssp_request.c b/drivers/scsi/isci/core/scic_sds_ssp_request.c deleted file mode 100644 index 3fdf68be7a4d..000000000000 --- a/drivers/scsi/isci/core/scic_sds_ssp_request.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "host.h" -#include "state_machine.h" -#include "scic_sds_request.h" -#include "scu_completion_codes.h" -#include "scu_task_context.h" - -/** - * This method processes the completions transport layer (TL) status to - * determine if the RAW task management frame was sent successfully. If the - * raw frame was sent successfully, then the state for the task request - * transitions to waiting for a response frame. - * @sci_req: This parameter specifies the request for which the TC - * completion was received. - * @completion_code: This parameter indicates the completion status information - * for the TC. - * - * Indicate if the tc completion handler was successful. SCI_SUCCESS currently - * this method always returns success. - */ -static enum sci_status scic_sds_ssp_task_request_await_tc_completion_tc_completion_handler( - struct scic_sds_request *sci_req, - u32 completion_code) -{ - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - scic_sds_request_set_status( - sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS - ); - - sci_base_state_machine_change_state( - &sci_req->started_substate_machine, - SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE - ); - break; - - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_ACK_NAK_TO): - /* - * Currently, the decision is to simply allow the task request to - * timeout if the task IU wasn't received successfully. - * There is a potential for receiving multiple task responses if we - * decide to send the task IU again. */ - dev_warn(scic_to_dev(sci_req->owning_controller), - "%s: TaskRequest:0x%p CompletionCode:%x - " - "ACK/NAK timeout\n", - __func__, - sci_req, - completion_code); - - sci_base_state_machine_change_state( - &sci_req->started_substate_machine, - SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE - ); - break; - - default: - /* - * All other completion status cause the IO to be complete. If a NAK - * was received, then it is up to the user to retry the request. */ - scic_sds_request_set_status( - sci_req, - SCU_NORMALIZE_COMPLETION_STATUS(completion_code), - SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR - ); - - sci_base_state_machine_change_state(&sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - break; - } - - return SCI_SUCCESS; -} - -/** - * This method is responsible for processing a terminate/abort request for this - * TC while the request is waiting for the task management response - * unsolicited frame. - * @sci_req: This parameter specifies the request for which the - * termination was requested. - * - * This method returns an indication as to whether the abort request was - * successfully handled. need to update to ensure the received UF doesn't cause - * damage to subsequent requests (i.e. put the extended tag in a holding - * pattern for this particular device). - */ -static enum sci_status scic_sds_ssp_task_request_await_tc_response_abort_handler( - struct scic_sds_request *request) -{ - sci_base_state_machine_change_state(&request->state_machine, - SCI_BASE_REQUEST_STATE_ABORTING); - sci_base_state_machine_change_state(&request->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - return SCI_SUCCESS; -} - -/** - * This method processes an unsolicited frame while the task mgmt request is - * waiting for a response frame. It will copy the response data, release - * the unsolicited frame, and transition the request to the - * SCI_BASE_REQUEST_STATE_COMPLETED state. - * @sci_req: This parameter specifies the request for which the - * unsolicited frame was received. - * @frame_index: This parameter indicates the unsolicited frame index that - * should contain the response. - * - * This method returns an indication of whether the TC response frame was - * handled successfully or not. SCI_SUCCESS Currently this value is always - * returned and indicates successful processing of the TC response. Should - * probably update to check frame type and make sure it is a response frame. - */ -static enum sci_status scic_sds_ssp_task_request_await_tc_response_frame_handler( - struct scic_sds_request *request, - u32 frame_index) -{ - scic_sds_io_request_copy_response(request); - - sci_base_state_machine_change_state(&request->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - scic_sds_controller_release_frame(request->owning_controller, - frame_index); - return SCI_SUCCESS; -} - -static const struct scic_sds_io_request_state_handler scic_sds_ssp_task_request_started_substate_handler_table[] = { - [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION] = { - .abort_handler = scic_sds_request_started_state_abort_handler, - .tc_completion_handler = scic_sds_ssp_task_request_await_tc_completion_tc_completion_handler, - }, - [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE] = { - .abort_handler = scic_sds_ssp_task_request_await_tc_response_abort_handler, - .frame_handler = scic_sds_ssp_task_request_await_tc_response_frame_handler, - } -}; - -/** - * This method performs the actions required when entering the - * SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION - * sub-state. This includes setting the IO request state handlers for this - * sub-state. - * @object: This parameter specifies the request object for which the sub-state - * change is occurring. - * - * none. - */ -static void scic_sds_io_request_started_task_mgmt_await_tc_completion_substate_enter( - void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_ssp_task_request_started_substate_handler_table, - SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION - ); -} - -/** - * This method performs the actions required when entering the - * SCIC_SDS_IO_REQUEST_STARTED_SUBSTATE_AWAIT_TC_RESPONSE sub-state. This - * includes setting the IO request state handlers for this sub-state. - * @object: This parameter specifies the request object for which the sub-state - * change is occurring. - * - * none. - */ -static void scic_sds_io_request_started_task_mgmt_await_task_response_substate_enter( - void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_ssp_task_request_started_substate_handler_table, - SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE - ); -} - -const struct sci_base_state scic_sds_io_request_started_task_mgmt_substate_table[] = { - [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION] = { - .enter_state = scic_sds_io_request_started_task_mgmt_await_tc_completion_substate_enter, - }, - [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE] = { - .enter_state = scic_sds_io_request_started_task_mgmt_await_task_response_substate_enter, - }, -}; - diff --git a/drivers/scsi/isci/core/scic_sds_stp_packet_request.h b/drivers/scsi/isci/core/scic_sds_stp_packet_request.h deleted file mode 100644 index e94d689e5103..000000000000 --- a/drivers/scsi/isci/core/scic_sds_stp_packet_request.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef _SCIC_SDS_STP_PACKET_REQUEST_H_ -#define _SCIC_SDS_STP_PACKET_REQUEST_H_ - -#include "scic_sds_stp_request.h" - -/** - * This file contains the structures and constants for PACKET protocol requests. - * - * - */ - - -/** - * - * - * This is the enumeration of the SATA PIO DATA IN started substate machine. - */ -enum _scic_sds_stp_packet_request_started_substates { - /** - * While in this state the IO request object is waiting for the TC completion - * notification for the H2D Register FIS - */ - SCIC_SDS_STP_PACKET_REQUEST_STARTED_PACKET_PHASE_AWAIT_TC_COMPLETION_SUBSTATE, - - /** - * While in this state the IO request object is waiting for either a PIO Setup. - */ - SCIC_SDS_STP_PACKET_REQUEST_STARTED_PACKET_PHASE_AWAIT_PIO_SETUP_SUBSTATE, - - /** - * While in this state the IO request object is waiting for TC completion for - * the Packet DMA DATA fis or Raw Frame. - */ - SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMMAND_PHASE_AWAIT_TC_COMPLETION_SUBSTATE, - - /** - * The non-data IO transit to this state in this state after receiving TC - * completion. While in this state IO request object is waiting for D2H status - * frame as UF. - */ - SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMMAND_PHASE_AWAIT_D2H_FIS_SUBSTATE, - - /** - * The IO transit to this state in this state if the previous TC completion status - * is not success and the atapi device is suspended due to target device failed the IO. - * While in this state IO request object is waiting for device coming out of the - * suspension state then complete the IO. - */ - SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMPLETION_DELAY_SUBSTATE, -}; - -#define scic_sds_stp_packet_request_construct(request) SCI_FAILURE -#define scu_stp_packet_request_command_phase_construct_task_context(reqeust, tc) -#define scu_stp_packet_request_command_phase_reconstruct_raw_frame_task_context(reqeust, tc) -#define scic_sds_stp_packet_request_process_status_fis(reqeust, fis) SCI_FAILURE -#define scic_sds_stp_packet_internal_request_sense_build_sgl(request) - -#endif /* _SCIC_SDS_STP_PACKET_REQUEST_H_ */ - diff --git a/drivers/scsi/isci/core/scic_sds_stp_pio_request.h b/drivers/scsi/isci/core/scic_sds_stp_pio_request.h deleted file mode 100644 index e015a1114760..000000000000 --- a/drivers/scsi/isci/core/scic_sds_stp_pio_request.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SCIC_SDS_SATA_PIO_REQUEST_H_ -#define _SCIC_SDS_SATA_PIO_REQUEST_H_ - -#include "scic_sds_request.h" -#include "scu_task_context.h" - -/** - * This file contains the structures and constants for SATA PIO requests. - * - * - */ - - -/** - * - * - * This is the enumeration of the SATA PIO DATA IN started substate machine. - */ -enum _scic_sds_stp_request_started_pio_substates { - /** - * While in this state the IO request object is waiting for the TC completion - * notification for the H2D Register FIS - */ - SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE, - - /** - * While in this state the IO request object is waiting for either a PIO Setup - * FIS or a D2H register FIS. The type of frame received is based on the - * result of the prior frame and line conditions. - */ - SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE, - - /** - * While in this state the IO request object is waiting for a DATA frame from - * the device. - */ - SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE, - - /** - * While in this state the IO request object is waiting to transmit the next data - * frame to the device. - */ - SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE, -}; - -struct scic_sds_stp_request; - - -#endif /* _SCIC_SDS_SATA_PIO_REQUEST_H_ */ diff --git a/drivers/scsi/isci/core/scic_sds_stp_request.c b/drivers/scsi/isci/core/scic_sds_stp_request.c deleted file mode 100644 index 308f486514e9..000000000000 --- a/drivers/scsi/isci/core/scic_sds_stp_request.c +++ /dev/null @@ -1,1594 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "sas.h" -#include "state_machine.h" -#include "scic_io_request.h" -#include "remote_device.h" -#include "scic_sds_request.h" -#include "scic_sds_stp_pio_request.h" -#include "scic_sds_stp_request.h" -#include "unsolicited_frame_control.h" -#include "sci_util.h" -#include "scu_completion_codes.h" -#include "scu_event_codes.h" -#include "scu_task_context.h" -#include "request.h" - -void scic_sds_stp_request_assign_buffers(struct scic_sds_request *sci_req) -{ - if (sci_req->was_tag_assigned_by_user == false) - sci_req->task_context_buffer = &sci_req->tc; -} - -/** - * This method is will fill in the SCU Task Context for any type of SATA - * request. This is called from the various SATA constructors. - * @sci_req: The general IO request object which is to be used in - * constructing the SCU task context. - * @task_context: The buffer pointer for the SCU task context which is being - * constructed. - * - * The general io request construction is complete. The buffer assignment for - * the command buffer is complete. none Revisit task context construction to - * determine what is common for SSP/SMP/STP task context structures. - */ -static void scu_sata_reqeust_construct_task_context( - struct scic_sds_request *sci_req, - struct scu_task_context *task_context) -{ - dma_addr_t dma_addr; - struct scic_sds_controller *controller; - struct scic_sds_remote_device *target_device; - struct scic_sds_port *target_port; - - controller = scic_sds_request_get_controller(sci_req); - target_device = scic_sds_request_get_device(sci_req); - target_port = scic_sds_request_get_port(sci_req); - - /* Fill in the TC with the its required data */ - task_context->abort = 0; - task_context->priority = SCU_TASK_PRIORITY_NORMAL; - task_context->initiator_request = 1; - task_context->connection_rate = target_device->connection_rate; - task_context->protocol_engine_index = - scic_sds_controller_get_protocol_engine_group(controller); - task_context->logical_port_index = - scic_sds_port_get_index(target_port); - task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_STP; - task_context->valid = SCU_TASK_CONTEXT_VALID; - task_context->context_type = SCU_TASK_CONTEXT_TYPE; - - task_context->remote_node_index = - scic_sds_remote_device_get_index(sci_req->target_device); - task_context->command_code = 0; - - task_context->link_layer_control = 0; - task_context->do_not_dma_ssp_good_response = 1; - task_context->strict_ordering = 0; - task_context->control_frame = 0; - task_context->timeout_enable = 0; - task_context->block_guard_enable = 0; - - task_context->address_modifier = 0; - task_context->task_phase = 0x01; - - task_context->ssp_command_iu_length = - (sizeof(struct host_to_dev_fis) - sizeof(u32)) / sizeof(u32); - - /* Set the first word of the H2D REG FIS */ - task_context->type.words[0] = *(u32 *)&sci_req->stp.cmd; - - if (sci_req->was_tag_assigned_by_user) { - /* - * Build the task context now since we have already read - * the data - */ - sci_req->post_context = - (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | - (scic_sds_controller_get_protocol_engine_group( - controller) << - SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | - (scic_sds_port_get_index(target_port) << - SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) | - scic_sds_io_tag_get_index(sci_req->io_tag)); - } else { - /* - * Build the task context now since we have already read - * the data. - * I/O tag index is not assigned because we have to wait - * until we get a TCi. - */ - sci_req->post_context = - (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | - (scic_sds_controller_get_protocol_engine_group( - controller) << - SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | - (scic_sds_port_get_index(target_port) << - SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)); - } - - /* - * Copy the physical address for the command buffer to the SCU Task - * Context. We must offset the command buffer by 4 bytes because the - * first 4 bytes are transfered in the body of the TC. - */ - dma_addr = scic_io_request_get_dma_addr(sci_req, - ((char *) &sci_req->stp.cmd) + - sizeof(u32)); - - task_context->command_iu_upper = upper_32_bits(dma_addr); - task_context->command_iu_lower = lower_32_bits(dma_addr); - - /* SATA Requests do not have a response buffer */ - task_context->response_iu_upper = 0; - task_context->response_iu_lower = 0; -} - -/** - * - * @sci_req: - * - * This method will perform any general sata request construction. What part of - * SATA IO request construction is general? none - */ -static void scic_sds_stp_non_ncq_request_construct( - struct scic_sds_request *sci_req) -{ - sci_req->has_started_substate_machine = true; -} - -/** - * - * @sci_req: This parameter specifies the request to be constructed as an - * optimized request. - * @optimized_task_type: This parameter specifies whether the request is to be - * an UDMA request or a NCQ request. - A value of 0 indicates UDMA. - A - * value of 1 indicates NCQ. - * - * This method will perform request construction common to all types of STP - * requests that are optimized by the silicon (i.e. UDMA, NCQ). This method - * returns an indication as to whether the construction was successful. - */ -static void scic_sds_stp_optimized_request_construct(struct scic_sds_request *sci_req, - u8 optimized_task_type, - u32 len, - enum dma_data_direction dir) -{ - struct scu_task_context *task_context = sci_req->task_context_buffer; - - /* Build the STP task context structure */ - scu_sata_reqeust_construct_task_context(sci_req, task_context); - - /* Copy over the SGL elements */ - scic_sds_request_build_sgl(sci_req); - - /* Copy over the number of bytes to be transfered */ - task_context->transfer_length_bytes = len; - - if (dir == DMA_TO_DEVICE) { - /* - * The difference between the DMA IN and DMA OUT request task type - * values are consistent with the difference between FPDMA READ - * and FPDMA WRITE values. Add the supplied task type parameter - * to this difference to set the task type properly for this - * DATA OUT (WRITE) case. */ - task_context->task_type = optimized_task_type + (SCU_TASK_TYPE_DMA_OUT - - SCU_TASK_TYPE_DMA_IN); - } else { - /* - * For the DATA IN (READ) case, simply save the supplied - * optimized task type. */ - task_context->task_type = optimized_task_type; - } -} - -/** - * - * @sci_req: This parameter specifies the request to be constructed. - * - * This method will construct the STP UDMA request and its associated TC data. - * This method returns an indication as to whether the construction was - * successful. SCI_SUCCESS Currently this method always returns this value. - */ -enum sci_status scic_sds_stp_ncq_request_construct(struct scic_sds_request *sci_req, - u32 len, - enum dma_data_direction dir) -{ - scic_sds_stp_optimized_request_construct(sci_req, - SCU_TASK_TYPE_FPDMAQ_READ, - len, dir); - return SCI_SUCCESS; -} - -/** - * scu_stp_raw_request_construct_task_context - - * @sci_req: This parameter specifies the STP request object for which to - * construct a RAW command frame task context. - * @task_context: This parameter specifies the SCU specific task context buffer - * to construct. - * - * This method performs the operations common to all SATA/STP requests - * utilizing the raw frame method. none - */ -static void scu_stp_raw_request_construct_task_context( - struct scic_sds_stp_request *stp_req, - struct scu_task_context *task_context) -{ - struct scic_sds_request *sci_req = to_sci_req(stp_req); - - scu_sata_reqeust_construct_task_context(sci_req, task_context); - - task_context->control_frame = 0; - task_context->priority = SCU_TASK_PRIORITY_NORMAL; - task_context->task_type = SCU_TASK_TYPE_SATA_RAW_FRAME; - task_context->type.stp.fis_type = FIS_REGH2D; - task_context->transfer_length_bytes = sizeof(struct host_to_dev_fis) - sizeof(u32); -} - -void scic_stp_io_request_set_ncq_tag( - struct scic_sds_request *req, - u16 ncq_tag) -{ - /** - * @note This could be made to return an error to the user if the user - * attempts to set the NCQ tag in the wrong state. - */ - req->task_context_buffer->type.stp.ncq_tag = ncq_tag; -} - -/** - * - * @sci_req: - * - * Get the next SGL element from the request. - Check on which SGL element pair - * we are working - if working on SLG pair element A - advance to element B - - * else - check to see if there are more SGL element pairs for this IO request - * - if there are more SGL element pairs - advance to the next pair and return - * element A struct scu_sgl_element* - */ -static struct scu_sgl_element *scic_sds_stp_request_pio_get_next_sgl(struct scic_sds_stp_request *stp_req) -{ - struct scu_sgl_element *current_sgl; - struct scic_sds_request *sci_req = to_sci_req(stp_req); - struct scic_sds_request_pio_sgl *pio_sgl = &stp_req->type.pio.request_current; - - if (pio_sgl->sgl_set == SCU_SGL_ELEMENT_PAIR_A) { - if (pio_sgl->sgl_pair->B.address_lower == 0 && - pio_sgl->sgl_pair->B.address_upper == 0) { - current_sgl = NULL; - } else { - pio_sgl->sgl_set = SCU_SGL_ELEMENT_PAIR_B; - current_sgl = &pio_sgl->sgl_pair->B; - } - } else { - if (pio_sgl->sgl_pair->next_pair_lower == 0 && - pio_sgl->sgl_pair->next_pair_upper == 0) { - current_sgl = NULL; - } else { - u64 phys_addr; - - phys_addr = pio_sgl->sgl_pair->next_pair_upper; - phys_addr <<= 32; - phys_addr |= pio_sgl->sgl_pair->next_pair_lower; - - pio_sgl->sgl_pair = scic_request_get_virt_addr(sci_req, phys_addr); - pio_sgl->sgl_set = SCU_SGL_ELEMENT_PAIR_A; - current_sgl = &pio_sgl->sgl_pair->A; - } - } - - return current_sgl; -} - -/** - * - * @sci_req: - * @completion_code: - * - * This method processes a TC completion. The expected TC completion is for - * the transmission of the H2D register FIS containing the SATA/STP non-data - * request. This method always successfully processes the TC completion. - * SCI_SUCCESS This value is always returned. - */ -static enum sci_status scic_sds_stp_request_non_data_await_h2d_tc_completion_handler( - struct scic_sds_request *sci_req, - u32 completion_code) -{ - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - scic_sds_request_set_status( - sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS - ); - - sci_base_state_machine_change_state( - &sci_req->started_substate_machine, - SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE - ); - break; - - default: - /* - * All other completion status cause the IO to be complete. If a NAK - * was received, then it is up to the user to retry the request. */ - scic_sds_request_set_status( - sci_req, - SCU_NORMALIZE_COMPLETION_STATUS(completion_code), - SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR - ); - - sci_base_state_machine_change_state( - &sci_req->state_machine, SCI_BASE_REQUEST_STATE_COMPLETED); - break; - } - - return SCI_SUCCESS; -} - -/** - * - * @request: This parameter specifies the request for which a frame has been - * received. - * @frame_index: This parameter specifies the index of the frame that has been - * received. - * - * This method processes frames received from the target while waiting for a - * device to host register FIS. If a non-register FIS is received during this - * time, it is treated as a protocol violation from an IO perspective. Indicate - * if the received frame was processed successfully. - */ -static enum sci_status scic_sds_stp_request_non_data_await_d2h_frame_handler( - struct scic_sds_request *sci_req, - u32 frame_index) -{ - enum sci_status status; - struct dev_to_host_fis *frame_header; - u32 *frame_buffer; - struct scic_sds_stp_request *stp_req = &sci_req->stp.req; - struct scic_sds_controller *scic = sci_req->owning_controller; - - status = scic_sds_unsolicited_frame_control_get_header(&scic->uf_control, - frame_index, - (void **)&frame_header); - - if (status != SCI_SUCCESS) { - dev_err(scic_to_dev(sci_req->owning_controller), - "%s: SCIC IO Request 0x%p could not get frame header " - "for frame index %d, status %x\n", - __func__, stp_req, frame_index, status); - - return status; - } - - switch (frame_header->fis_type) { - case FIS_REGD2H: - scic_sds_unsolicited_frame_control_get_buffer(&scic->uf_control, - frame_index, - (void **)&frame_buffer); - - scic_sds_controller_copy_sata_response(&sci_req->stp.rsp, - frame_header, - frame_buffer); - - /* The command has completed with error */ - scic_sds_request_set_status(sci_req, SCU_TASK_DONE_CHECK_RESPONSE, - SCI_FAILURE_IO_RESPONSE_VALID); - break; - - default: - dev_warn(scic_to_dev(scic), - "%s: IO Request:0x%p Frame Id:%d protocol " - "violation occurred\n", __func__, stp_req, - frame_index); - - scic_sds_request_set_status(sci_req, SCU_TASK_DONE_UNEXP_FIS, - SCI_FAILURE_PROTOCOL_VIOLATION); - break; - } - - sci_base_state_machine_change_state(&sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - - /* Frame has been decoded return it to the controller */ - scic_sds_controller_release_frame(scic, frame_index); - - return status; -} - -/* --------------------------------------------------------------------------- */ - -static const struct scic_sds_io_request_state_handler scic_sds_stp_request_started_non_data_substate_handler_table[] = { - [SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE] = { - .abort_handler = scic_sds_request_started_state_abort_handler, - .tc_completion_handler = scic_sds_stp_request_non_data_await_h2d_tc_completion_handler, - }, - [SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE] = { - .abort_handler = scic_sds_request_started_state_abort_handler, - .frame_handler = scic_sds_stp_request_non_data_await_d2h_frame_handler, - } -}; - -static void scic_sds_stp_request_started_non_data_await_h2d_completion_enter( - void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_stp_request_started_non_data_substate_handler_table, - SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE - ); - - scic_sds_remote_device_set_working_request( - sci_req->target_device, sci_req - ); -} - -static void scic_sds_stp_request_started_non_data_await_d2h_enter(void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_stp_request_started_non_data_substate_handler_table, - SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE - ); -} - -/* --------------------------------------------------------------------------- */ - -static const struct sci_base_state scic_sds_stp_request_started_non_data_substate_table[] = { - [SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE] = { - .enter_state = scic_sds_stp_request_started_non_data_await_h2d_completion_enter, - }, - [SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE] = { - .enter_state = scic_sds_stp_request_started_non_data_await_d2h_enter, - }, -}; - -enum sci_status scic_sds_stp_non_data_request_construct(struct scic_sds_request *sci_req) -{ - struct scic_sds_stp_request *stp_req = &sci_req->stp.req; - - scic_sds_stp_non_ncq_request_construct(sci_req); - - /* Build the STP task context structure */ - scu_stp_raw_request_construct_task_context(stp_req, sci_req->task_context_buffer); - - sci_base_state_machine_construct(&sci_req->started_substate_machine, - sci_req, - scic_sds_stp_request_started_non_data_substate_table, - SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE); - - return SCI_SUCCESS; -} - -#define SCU_MAX_FRAME_BUFFER_SIZE 0x400 /* 1K is the maximum SCU frame data payload */ - -/* transmit DATA_FIS from (current sgl + offset) for input - * parameter length. current sgl and offset is alreay stored in the IO request - */ -static enum sci_status scic_sds_stp_request_pio_data_out_trasmit_data_frame( - struct scic_sds_request *sci_req, - u32 length) -{ - struct scic_sds_controller *scic = sci_req->owning_controller; - struct scic_sds_stp_request *stp_req = &sci_req->stp.req; - struct scu_task_context *task_context; - struct scu_sgl_element *current_sgl; - - /* Recycle the TC and reconstruct it for sending out DATA FIS containing - * for the data from current_sgl+offset for the input length - */ - task_context = scic_sds_controller_get_task_context_buffer(scic, - sci_req->io_tag); - - if (stp_req->type.pio.request_current.sgl_set == SCU_SGL_ELEMENT_PAIR_A) - current_sgl = &stp_req->type.pio.request_current.sgl_pair->A; - else - current_sgl = &stp_req->type.pio.request_current.sgl_pair->B; - - /* update the TC */ - task_context->command_iu_upper = current_sgl->address_upper; - task_context->command_iu_lower = current_sgl->address_lower; - task_context->transfer_length_bytes = length; - task_context->type.stp.fis_type = FIS_DATA; - - /* send the new TC out. */ - return scic_controller_continue_io(sci_req); -} - -static enum sci_status scic_sds_stp_request_pio_data_out_transmit_data(struct scic_sds_request *sci_req) -{ - - struct scu_sgl_element *current_sgl; - u32 sgl_offset; - u32 remaining_bytes_in_current_sgl = 0; - enum sci_status status = SCI_SUCCESS; - struct scic_sds_stp_request *stp_req = &sci_req->stp.req; - - sgl_offset = stp_req->type.pio.request_current.sgl_offset; - - if (stp_req->type.pio.request_current.sgl_set == SCU_SGL_ELEMENT_PAIR_A) { - current_sgl = &(stp_req->type.pio.request_current.sgl_pair->A); - remaining_bytes_in_current_sgl = stp_req->type.pio.request_current.sgl_pair->A.length - sgl_offset; - } else { - current_sgl = &(stp_req->type.pio.request_current.sgl_pair->B); - remaining_bytes_in_current_sgl = stp_req->type.pio.request_current.sgl_pair->B.length - sgl_offset; - } - - - if (stp_req->type.pio.pio_transfer_bytes > 0) { - if (stp_req->type.pio.pio_transfer_bytes >= remaining_bytes_in_current_sgl) { - /* recycle the TC and send the H2D Data FIS from (current sgl + sgl_offset) and length = remaining_bytes_in_current_sgl */ - status = scic_sds_stp_request_pio_data_out_trasmit_data_frame(sci_req, remaining_bytes_in_current_sgl); - if (status == SCI_SUCCESS) { - stp_req->type.pio.pio_transfer_bytes -= remaining_bytes_in_current_sgl; - - /* update the current sgl, sgl_offset and save for future */ - current_sgl = scic_sds_stp_request_pio_get_next_sgl(stp_req); - sgl_offset = 0; - } - } else if (stp_req->type.pio.pio_transfer_bytes < remaining_bytes_in_current_sgl) { - /* recycle the TC and send the H2D Data FIS from (current sgl + sgl_offset) and length = type.pio.pio_transfer_bytes */ - scic_sds_stp_request_pio_data_out_trasmit_data_frame(sci_req, stp_req->type.pio.pio_transfer_bytes); - - if (status == SCI_SUCCESS) { - /* Sgl offset will be adjusted and saved for future */ - sgl_offset += stp_req->type.pio.pio_transfer_bytes; - current_sgl->address_lower += stp_req->type.pio.pio_transfer_bytes; - stp_req->type.pio.pio_transfer_bytes = 0; - } - } - } - - if (status == SCI_SUCCESS) { - stp_req->type.pio.request_current.sgl_offset = sgl_offset; - } - - return status; -} - -/** - * - * @stp_request: The request that is used for the SGL processing. - * @data_buffer: The buffer of data to be copied. - * @length: The length of the data transfer. - * - * Copy the data from the buffer for the length specified to the IO reqeust SGL - * specified data region. enum sci_status - */ -static enum sci_status -scic_sds_stp_request_pio_data_in_copy_data_buffer(struct scic_sds_stp_request *stp_req, - u8 *data_buf, u32 len) -{ - struct scic_sds_request *sci_req; - struct isci_request *ireq; - u8 *src_addr; - int copy_len; - struct sas_task *task; - struct scatterlist *sg; - void *kaddr; - int total_len = len; - - sci_req = to_sci_req(stp_req); - ireq = sci_req_to_ireq(sci_req); - task = isci_request_access_task(ireq); - src_addr = data_buf; - - if (task->num_scatter > 0) { - sg = task->scatter; - - while (total_len > 0) { - struct page *page = sg_page(sg); - - copy_len = min_t(int, total_len, sg_dma_len(sg)); - kaddr = kmap_atomic(page, KM_IRQ0); - memcpy(kaddr + sg->offset, src_addr, copy_len); - kunmap_atomic(kaddr, KM_IRQ0); - total_len -= copy_len; - src_addr += copy_len; - sg = sg_next(sg); - } - } else { - BUG_ON(task->total_xfer_len < total_len); - memcpy(task->scatter, src_addr, total_len); - } - - return SCI_SUCCESS; -} - -/** - * - * @sci_req: The PIO DATA IN request that is to receive the data. - * @data_buffer: The buffer to copy from. - * - * Copy the data buffer to the io request data region. enum sci_status - */ -static enum sci_status scic_sds_stp_request_pio_data_in_copy_data( - struct scic_sds_stp_request *sci_req, - u8 *data_buffer) -{ - enum sci_status status; - - /* - * If there is less than 1K remaining in the transfer request - * copy just the data for the transfer */ - if (sci_req->type.pio.pio_transfer_bytes < SCU_MAX_FRAME_BUFFER_SIZE) { - status = scic_sds_stp_request_pio_data_in_copy_data_buffer( - sci_req, data_buffer, sci_req->type.pio.pio_transfer_bytes); - - if (status == SCI_SUCCESS) - sci_req->type.pio.pio_transfer_bytes = 0; - } else { - /* We are transfering the whole frame so copy */ - status = scic_sds_stp_request_pio_data_in_copy_data_buffer( - sci_req, data_buffer, SCU_MAX_FRAME_BUFFER_SIZE); - - if (status == SCI_SUCCESS) - sci_req->type.pio.pio_transfer_bytes -= SCU_MAX_FRAME_BUFFER_SIZE; - } - - return status; -} - -/** - * - * @sci_req: - * @completion_code: - * - * enum sci_status - */ -static enum sci_status scic_sds_stp_request_pio_await_h2d_completion_tc_completion_handler( - struct scic_sds_request *sci_req, - u32 completion_code) -{ - enum sci_status status = SCI_SUCCESS; - - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - scic_sds_request_set_status( - sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS - ); - - sci_base_state_machine_change_state( - &sci_req->started_substate_machine, - SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE - ); - break; - - default: - /* - * All other completion status cause the IO to be complete. If a NAK - * was received, then it is up to the user to retry the request. */ - scic_sds_request_set_status( - sci_req, - SCU_NORMALIZE_COMPLETION_STATUS(completion_code), - SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR - ); - - sci_base_state_machine_change_state( - &sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED - ); - break; - } - - return status; -} - -static enum sci_status scic_sds_stp_request_pio_await_frame_frame_handler(struct scic_sds_request *sci_req, - u32 frame_index) -{ - struct scic_sds_controller *scic = sci_req->owning_controller; - struct scic_sds_stp_request *stp_req = &sci_req->stp.req; - struct isci_request *ireq = sci_req_to_ireq(sci_req); - struct sas_task *task = isci_request_access_task(ireq); - struct dev_to_host_fis *frame_header; - enum sci_status status; - u32 *frame_buffer; - - status = scic_sds_unsolicited_frame_control_get_header(&scic->uf_control, - frame_index, - (void **)&frame_header); - - if (status != SCI_SUCCESS) { - dev_err(scic_to_dev(scic), - "%s: SCIC IO Request 0x%p could not get frame header " - "for frame index %d, status %x\n", - __func__, stp_req, frame_index, status); - return status; - } - - switch (frame_header->fis_type) { - case FIS_PIO_SETUP: - /* Get from the frame buffer the PIO Setup Data */ - scic_sds_unsolicited_frame_control_get_buffer(&scic->uf_control, - frame_index, - (void **)&frame_buffer); - - /* Get the data from the PIO Setup The SCU Hardware returns - * first word in the frame_header and the rest of the data is in - * the frame buffer so we need to back up one dword - */ - - /* transfer_count: first 16bits in the 4th dword */ - stp_req->type.pio.pio_transfer_bytes = frame_buffer[3] & 0xffff; - - /* ending_status: 4th byte in the 3rd dword */ - stp_req->type.pio.ending_status = (frame_buffer[2] >> 24) & 0xff; - - scic_sds_controller_copy_sata_response(&sci_req->stp.rsp, - frame_header, - frame_buffer); - - sci_req->stp.rsp.status = stp_req->type.pio.ending_status; - - /* The next state is dependent on whether the - * request was PIO Data-in or Data out - */ - if (task->data_dir == DMA_FROM_DEVICE) { - sci_base_state_machine_change_state(&sci_req->started_substate_machine, - SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE); - } else if (task->data_dir == DMA_TO_DEVICE) { - /* Transmit data */ - status = scic_sds_stp_request_pio_data_out_transmit_data(sci_req); - if (status != SCI_SUCCESS) - break; - sci_base_state_machine_change_state(&sci_req->started_substate_machine, - SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE); - } - break; - case FIS_SETDEVBITS: - sci_base_state_machine_change_state(&sci_req->started_substate_machine, - SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE); - break; - case FIS_REGD2H: - if (frame_header->status & ATA_BUSY) { - /* Now why is the drive sending a D2H Register FIS when - * it is still busy? Do nothing since we are still in - * the right state. - */ - dev_dbg(scic_to_dev(scic), - "%s: SCIC PIO Request 0x%p received " - "D2H Register FIS with BSY status " - "0x%x\n", __func__, stp_req, - frame_header->status); - break; - } - - scic_sds_unsolicited_frame_control_get_buffer(&scic->uf_control, - frame_index, - (void **)&frame_buffer); - - scic_sds_controller_copy_sata_response(&sci_req->stp.req, - frame_header, - frame_buffer); - - scic_sds_request_set_status(sci_req, - SCU_TASK_DONE_CHECK_RESPONSE, - SCI_FAILURE_IO_RESPONSE_VALID); - - sci_base_state_machine_change_state(&sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - break; - default: - /* FIXME: what do we do here? */ - break; - } - - /* Frame is decoded return it to the controller */ - scic_sds_controller_release_frame(scic, frame_index); - - return status; -} - -static enum sci_status scic_sds_stp_request_pio_data_in_await_data_frame_handler(struct scic_sds_request *sci_req, - u32 frame_index) -{ - enum sci_status status; - struct dev_to_host_fis *frame_header; - struct sata_fis_data *frame_buffer; - struct scic_sds_stp_request *stp_req = &sci_req->stp.req; - struct scic_sds_controller *scic = sci_req->owning_controller; - - status = scic_sds_unsolicited_frame_control_get_header(&scic->uf_control, - frame_index, - (void **)&frame_header); - - if (status != SCI_SUCCESS) { - dev_err(scic_to_dev(scic), - "%s: SCIC IO Request 0x%p could not get frame header " - "for frame index %d, status %x\n", - __func__, stp_req, frame_index, status); - return status; - } - - if (frame_header->fis_type == FIS_DATA) { - if (stp_req->type.pio.request_current.sgl_pair == NULL) { - sci_req->saved_rx_frame_index = frame_index; - stp_req->type.pio.pio_transfer_bytes = 0; - } else { - scic_sds_unsolicited_frame_control_get_buffer(&scic->uf_control, - frame_index, - (void **)&frame_buffer); - - status = scic_sds_stp_request_pio_data_in_copy_data(stp_req, - (u8 *)frame_buffer); - - /* Frame is decoded return it to the controller */ - scic_sds_controller_release_frame(scic, frame_index); - } - - /* Check for the end of the transfer, are there more - * bytes remaining for this data transfer - */ - if (status != SCI_SUCCESS || - stp_req->type.pio.pio_transfer_bytes != 0) - return status; - - if ((stp_req->type.pio.ending_status & ATA_BUSY) == 0) { - scic_sds_request_set_status(sci_req, - SCU_TASK_DONE_CHECK_RESPONSE, - SCI_FAILURE_IO_RESPONSE_VALID); - - sci_base_state_machine_change_state(&sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - } else { - sci_base_state_machine_change_state(&sci_req->started_substate_machine, - SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE); - } - } else { - dev_err(scic_to_dev(scic), - "%s: SCIC PIO Request 0x%p received frame %d " - "with fis type 0x%02x when expecting a data " - "fis.\n", __func__, stp_req, frame_index, - frame_header->fis_type); - - scic_sds_request_set_status(sci_req, - SCU_TASK_DONE_GOOD, - SCI_FAILURE_IO_REQUIRES_SCSI_ABORT); - - sci_base_state_machine_change_state(&sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - - /* Frame is decoded return it to the controller */ - scic_sds_controller_release_frame(scic, frame_index); - } - - return status; -} - - -/** - * - * @sci_req: - * @completion_code: - * - * enum sci_status - */ -static enum sci_status scic_sds_stp_request_pio_data_out_await_data_transmit_completion_tc_completion_handler( - - struct scic_sds_request *sci_req, - u32 completion_code) -{ - enum sci_status status = SCI_SUCCESS; - bool all_frames_transferred = false; - struct scic_sds_stp_request *stp_req = &sci_req->stp.req; - - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - /* Transmit data */ - if (stp_req->type.pio.pio_transfer_bytes != 0) { - status = scic_sds_stp_request_pio_data_out_transmit_data(sci_req); - if (status == SCI_SUCCESS) { - if (stp_req->type.pio.pio_transfer_bytes == 0) - all_frames_transferred = true; - } - } else if (stp_req->type.pio.pio_transfer_bytes == 0) { - /* - * this will happen if the all data is written at the - * first time after the pio setup fis is received - */ - all_frames_transferred = true; - } - - /* all data transferred. */ - if (all_frames_transferred) { - /* - * Change the state to SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_FRAME_SUBSTATE - * and wait for PIO_SETUP fis / or D2H REg fis. */ - sci_base_state_machine_change_state( - &sci_req->started_substate_machine, - SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE - ); - } - break; - - default: - /* - * All other completion status cause the IO to be complete. If a NAK - * was received, then it is up to the user to retry the request. */ - scic_sds_request_set_status( - sci_req, - SCU_NORMALIZE_COMPLETION_STATUS(completion_code), - SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR - ); - - sci_base_state_machine_change_state( - &sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED - ); - break; - } - - return status; -} - -/** - * - * @request: This is the request which is receiving the event. - * @event_code: This is the event code that the request on which the request is - * expected to take action. - * - * This method will handle any link layer events while waiting for the data - * frame. enum sci_status SCI_SUCCESS SCI_FAILURE - */ -static enum sci_status scic_sds_stp_request_pio_data_in_await_data_event_handler( - struct scic_sds_request *request, - u32 event_code) -{ - enum sci_status status; - - switch (scu_get_event_specifier(event_code)) { - case SCU_TASK_DONE_CRC_ERR << SCU_EVENT_SPECIFIC_CODE_SHIFT: - /* - * We are waiting for data and the SCU has R_ERR the data frame. - * Go back to waiting for the D2H Register FIS */ - sci_base_state_machine_change_state( - &request->started_substate_machine, - SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE - ); - - status = SCI_SUCCESS; - break; - - default: - dev_err(scic_to_dev(request->owning_controller), - "%s: SCIC PIO Request 0x%p received unexpected " - "event 0x%08x\n", - __func__, request, event_code); - - /* / @todo Should we fail the PIO request when we get an unexpected event? */ - status = SCI_FAILURE; - break; - } - - return status; -} - -/* --------------------------------------------------------------------------- */ - -static const struct scic_sds_io_request_state_handler scic_sds_stp_request_started_pio_substate_handler_table[] = { - [SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE] = { - .abort_handler = scic_sds_request_started_state_abort_handler, - .tc_completion_handler = scic_sds_stp_request_pio_await_h2d_completion_tc_completion_handler, - }, - [SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE] = { - .abort_handler = scic_sds_request_started_state_abort_handler, - .frame_handler = scic_sds_stp_request_pio_await_frame_frame_handler - }, - [SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE] = { - .abort_handler = scic_sds_request_started_state_abort_handler, - .event_handler = scic_sds_stp_request_pio_data_in_await_data_event_handler, - .frame_handler = scic_sds_stp_request_pio_data_in_await_data_frame_handler - }, - [SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE] = { - .abort_handler = scic_sds_request_started_state_abort_handler, - .tc_completion_handler = scic_sds_stp_request_pio_data_out_await_data_transmit_completion_tc_completion_handler, - } -}; - -static void scic_sds_stp_request_started_pio_await_h2d_completion_enter( - void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_stp_request_started_pio_substate_handler_table, - SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE - ); - - scic_sds_remote_device_set_working_request( - sci_req->target_device, sci_req); -} - -static void scic_sds_stp_request_started_pio_await_frame_enter(void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_stp_request_started_pio_substate_handler_table, - SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE - ); -} - -static void scic_sds_stp_request_started_pio_data_in_await_data_enter( - void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_stp_request_started_pio_substate_handler_table, - SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE - ); -} - -static void scic_sds_stp_request_started_pio_data_out_transmit_data_enter( - void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_stp_request_started_pio_substate_handler_table, - SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE - ); -} - -/* --------------------------------------------------------------------------- */ - -static const struct sci_base_state scic_sds_stp_request_started_pio_substate_table[] = { - [SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE] = { - .enter_state = scic_sds_stp_request_started_pio_await_h2d_completion_enter, - }, - [SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE] = { - .enter_state = scic_sds_stp_request_started_pio_await_frame_enter, - }, - [SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE] = { - .enter_state = scic_sds_stp_request_started_pio_data_in_await_data_enter, - }, - [SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE] = { - .enter_state = scic_sds_stp_request_started_pio_data_out_transmit_data_enter, - } -}; - -enum sci_status -scic_sds_stp_pio_request_construct(struct scic_sds_request *sci_req, - bool copy_rx_frame) -{ - struct scic_sds_stp_request *stp_req = &sci_req->stp.req; - struct scic_sds_stp_pio_request *pio = &stp_req->type.pio; - - scic_sds_stp_non_ncq_request_construct(sci_req); - - scu_stp_raw_request_construct_task_context(stp_req, - sci_req->task_context_buffer); - - pio->current_transfer_bytes = 0; - pio->ending_error = 0; - pio->ending_status = 0; - - pio->request_current.sgl_offset = 0; - pio->request_current.sgl_set = SCU_SGL_ELEMENT_PAIR_A; - - if (copy_rx_frame) { - scic_sds_request_build_sgl(sci_req); - /* Since the IO request copy of the TC contains the same data as - * the actual TC this pointer is vaild for either. - */ - pio->request_current.sgl_pair = &sci_req->task_context_buffer->sgl_pair_ab; - } else { - /* The user does not want the data copied to the SGL buffer location */ - pio->request_current.sgl_pair = NULL; - } - - sci_base_state_machine_construct(&sci_req->started_substate_machine, - sci_req, - scic_sds_stp_request_started_pio_substate_table, - SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE); - - return SCI_SUCCESS; -} - -static void scic_sds_stp_request_udma_complete_request( - struct scic_sds_request *request, - u32 scu_status, - enum sci_status sci_status) -{ - scic_sds_request_set_status(request, scu_status, sci_status); - sci_base_state_machine_change_state(&request->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); -} - -static enum sci_status scic_sds_stp_request_udma_general_frame_handler(struct scic_sds_request *sci_req, - u32 frame_index) -{ - struct scic_sds_controller *scic = sci_req->owning_controller; - struct dev_to_host_fis *frame_header; - enum sci_status status; - u32 *frame_buffer; - - status = scic_sds_unsolicited_frame_control_get_header(&scic->uf_control, - frame_index, - (void **)&frame_header); - - if ((status == SCI_SUCCESS) && - (frame_header->fis_type == FIS_REGD2H)) { - scic_sds_unsolicited_frame_control_get_buffer(&scic->uf_control, - frame_index, - (void **)&frame_buffer); - - scic_sds_controller_copy_sata_response(&sci_req->stp.rsp, - frame_header, - frame_buffer); - } - - scic_sds_controller_release_frame(scic, frame_index); - - return status; -} - -static enum sci_status scic_sds_stp_request_udma_await_tc_completion_tc_completion_handler( - struct scic_sds_request *sci_req, - u32 completion_code) -{ - enum sci_status status = SCI_SUCCESS; - - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - scic_sds_stp_request_udma_complete_request(sci_req, - SCU_TASK_DONE_GOOD, - SCI_SUCCESS); - break; - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_FIS): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR): - /* - * We must check ther response buffer to see if the D2H Register FIS was - * received before we got the TC completion. */ - if (sci_req->stp.rsp.fis_type == FIS_REGD2H) { - scic_sds_remote_device_suspend(sci_req->target_device, - SCU_EVENT_SPECIFIC(SCU_NORMALIZE_COMPLETION_STATUS(completion_code))); - - scic_sds_stp_request_udma_complete_request(sci_req, - SCU_TASK_DONE_CHECK_RESPONSE, - SCI_FAILURE_IO_RESPONSE_VALID); - } else { - /* - * If we have an error completion status for the TC then we can expect a - * D2H register FIS from the device so we must change state to wait for it */ - sci_base_state_machine_change_state(&sci_req->started_substate_machine, - SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE); - } - break; - - /* - * / @todo Check to see if any of these completion status need to wait for - * / the device to host register fis. */ - /* / @todo We can retry the command for SCU_TASK_DONE_CMD_LL_R_ERR - this comes only for B0 */ - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_INV_FIS_LEN): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_MAX_PLD_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_R_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CMD_LL_R_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CRC_ERR): - scic_sds_remote_device_suspend(sci_req->target_device, - SCU_EVENT_SPECIFIC(SCU_NORMALIZE_COMPLETION_STATUS(completion_code))); - /* Fall through to the default case */ - default: - /* All other completion status cause the IO to be complete. */ - scic_sds_stp_request_udma_complete_request(sci_req, - SCU_NORMALIZE_COMPLETION_STATUS(completion_code), - SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR); - break; - } - - return status; -} - -static enum sci_status scic_sds_stp_request_udma_await_d2h_reg_fis_frame_handler( - struct scic_sds_request *sci_req, - u32 frame_index) -{ - enum sci_status status; - - /* Use the general frame handler to copy the resposne data */ - status = scic_sds_stp_request_udma_general_frame_handler(sci_req, frame_index); - - if (status != SCI_SUCCESS) - return status; - - scic_sds_stp_request_udma_complete_request(sci_req, - SCU_TASK_DONE_CHECK_RESPONSE, - SCI_FAILURE_IO_RESPONSE_VALID); - - return status; -} - -/* --------------------------------------------------------------------------- */ - -static const struct scic_sds_io_request_state_handler scic_sds_stp_request_started_udma_substate_handler_table[] = { - [SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE] = { - .abort_handler = scic_sds_request_started_state_abort_handler, - .tc_completion_handler = scic_sds_stp_request_udma_await_tc_completion_tc_completion_handler, - .frame_handler = scic_sds_stp_request_udma_general_frame_handler, - }, - [SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE] = { - .abort_handler = scic_sds_request_started_state_abort_handler, - .frame_handler = scic_sds_stp_request_udma_await_d2h_reg_fis_frame_handler, - }, -}; - -static void scic_sds_stp_request_started_udma_await_tc_completion_enter( - void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_stp_request_started_udma_substate_handler_table, - SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE - ); -} - -/** - * - * - * This state is entered when there is an TC completion failure. The hardware - * received an unexpected condition while processing the IO request and now - * will UF the D2H register FIS to complete the IO. - */ -static void scic_sds_stp_request_started_udma_await_d2h_reg_fis_enter( - void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_stp_request_started_udma_substate_handler_table, - SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE - ); -} - -/* --------------------------------------------------------------------------- */ - -static const struct sci_base_state scic_sds_stp_request_started_udma_substate_table[] = { - [SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE] = { - .enter_state = scic_sds_stp_request_started_udma_await_tc_completion_enter, - }, - [SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE] = { - .enter_state = scic_sds_stp_request_started_udma_await_d2h_reg_fis_enter, - }, -}; - -enum sci_status scic_sds_stp_udma_request_construct(struct scic_sds_request *sci_req, - u32 len, - enum dma_data_direction dir) -{ - scic_sds_stp_non_ncq_request_construct(sci_req); - - scic_sds_stp_optimized_request_construct(sci_req, SCU_TASK_TYPE_DMA_IN, - len, dir); - - sci_base_state_machine_construct( - &sci_req->started_substate_machine, - sci_req, - scic_sds_stp_request_started_udma_substate_table, - SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE - ); - - return SCI_SUCCESS; -} - -/** - * - * @sci_req: - * @completion_code: - * - * This method processes a TC completion. The expected TC completion is for - * the transmission of the H2D register FIS containing the SATA/STP non-data - * request. This method always successfully processes the TC completion. - * SCI_SUCCESS This value is always returned. - */ -static enum sci_status scic_sds_stp_request_soft_reset_await_h2d_asserted_tc_completion_handler( - struct scic_sds_request *sci_req, - u32 completion_code) -{ - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - scic_sds_request_set_status( - sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS - ); - - sci_base_state_machine_change_state( - &sci_req->started_substate_machine, - SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE - ); - break; - - default: - /* - * All other completion status cause the IO to be complete. If a NAK - * was received, then it is up to the user to retry the request. */ - scic_sds_request_set_status( - sci_req, - SCU_NORMALIZE_COMPLETION_STATUS(completion_code), - SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR - ); - - sci_base_state_machine_change_state( - &sci_req->state_machine, SCI_BASE_REQUEST_STATE_COMPLETED); - break; - } - - return SCI_SUCCESS; -} - -/** - * - * @sci_req: - * @completion_code: - * - * This method processes a TC completion. The expected TC completion is for - * the transmission of the H2D register FIS containing the SATA/STP non-data - * request. This method always successfully processes the TC completion. - * SCI_SUCCESS This value is always returned. - */ -static enum sci_status scic_sds_stp_request_soft_reset_await_h2d_diagnostic_tc_completion_handler( - struct scic_sds_request *sci_req, - u32 completion_code) -{ - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - scic_sds_request_set_status( - sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS - ); - - sci_base_state_machine_change_state( - &sci_req->started_substate_machine, - SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE - ); - break; - - default: - /* - * All other completion status cause the IO to be complete. If a NAK - * was received, then it is up to the user to retry the request. */ - scic_sds_request_set_status( - sci_req, - SCU_NORMALIZE_COMPLETION_STATUS(completion_code), - SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR - ); - - sci_base_state_machine_change_state(&sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - break; - } - - return SCI_SUCCESS; -} - -/** - * - * @request: This parameter specifies the request for which a frame has been - * received. - * @frame_index: This parameter specifies the index of the frame that has been - * received. - * - * This method processes frames received from the target while waiting for a - * device to host register FIS. If a non-register FIS is received during this - * time, it is treated as a protocol violation from an IO perspective. Indicate - * if the received frame was processed successfully. - */ -static enum sci_status scic_sds_stp_request_soft_reset_await_d2h_frame_handler( - struct scic_sds_request *sci_req, - u32 frame_index) -{ - enum sci_status status; - struct dev_to_host_fis *frame_header; - u32 *frame_buffer; - struct scic_sds_stp_request *stp_req = &sci_req->stp.req; - struct scic_sds_controller *scic = sci_req->owning_controller; - - status = scic_sds_unsolicited_frame_control_get_header(&scic->uf_control, - frame_index, - (void **)&frame_header); - if (status != SCI_SUCCESS) { - dev_err(scic_to_dev(scic), - "%s: SCIC IO Request 0x%p could not get frame header " - "for frame index %d, status %x\n", - __func__, stp_req, frame_index, status); - return status; - } - - switch (frame_header->fis_type) { - case FIS_REGD2H: - scic_sds_unsolicited_frame_control_get_buffer(&scic->uf_control, - frame_index, - (void **)&frame_buffer); - - scic_sds_controller_copy_sata_response(&sci_req->stp.rsp, - frame_header, - frame_buffer); - - /* The command has completed with error */ - scic_sds_request_set_status(sci_req, - SCU_TASK_DONE_CHECK_RESPONSE, - SCI_FAILURE_IO_RESPONSE_VALID); - break; - - default: - dev_warn(scic_to_dev(scic), - "%s: IO Request:0x%p Frame Id:%d protocol " - "violation occurred\n", __func__, stp_req, - frame_index); - - scic_sds_request_set_status(sci_req, SCU_TASK_DONE_UNEXP_FIS, - SCI_FAILURE_PROTOCOL_VIOLATION); - break; - } - - sci_base_state_machine_change_state(&sci_req->state_machine, - SCI_BASE_REQUEST_STATE_COMPLETED); - - /* Frame has been decoded return it to the controller */ - scic_sds_controller_release_frame(scic, frame_index); - - return status; -} - -/* --------------------------------------------------------------------------- */ - -static const struct scic_sds_io_request_state_handler scic_sds_stp_request_started_soft_reset_substate_handler_table[] = { - [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE] = { - .abort_handler = scic_sds_request_started_state_abort_handler, - .tc_completion_handler = scic_sds_stp_request_soft_reset_await_h2d_asserted_tc_completion_handler, - }, - [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE] = { - .abort_handler = scic_sds_request_started_state_abort_handler, - .tc_completion_handler = scic_sds_stp_request_soft_reset_await_h2d_diagnostic_tc_completion_handler, - }, - [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE] = { - .abort_handler = scic_sds_request_started_state_abort_handler, - .frame_handler = scic_sds_stp_request_soft_reset_await_d2h_frame_handler, - }, -}; - -static void scic_sds_stp_request_started_soft_reset_await_h2d_asserted_completion_enter( - void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_stp_request_started_soft_reset_substate_handler_table, - SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE - ); - - scic_sds_remote_device_set_working_request( - sci_req->target_device, sci_req - ); -} - -static void scic_sds_stp_request_started_soft_reset_await_h2d_diagnostic_completion_enter( - void *object) -{ - struct scic_sds_request *sci_req = object; - struct scu_task_context *task_context; - struct host_to_dev_fis *h2d_fis; - enum sci_status status; - - /* Clear the SRST bit */ - h2d_fis = &sci_req->stp.cmd; - h2d_fis->control = 0; - - /* Clear the TC control bit */ - task_context = scic_sds_controller_get_task_context_buffer( - sci_req->owning_controller, sci_req->io_tag); - task_context->control_frame = 0; - - status = scic_controller_continue_io(sci_req); - if (status == SCI_SUCCESS) { - SET_STATE_HANDLER( - sci_req, - scic_sds_stp_request_started_soft_reset_substate_handler_table, - SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE - ); - } -} - -static void scic_sds_stp_request_started_soft_reset_await_d2h_response_enter( - void *object) -{ - struct scic_sds_request *sci_req = object; - - SET_STATE_HANDLER( - sci_req, - scic_sds_stp_request_started_soft_reset_substate_handler_table, - SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE - ); -} - -static const struct sci_base_state scic_sds_stp_request_started_soft_reset_substate_table[] = { - [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE] = { - .enter_state = scic_sds_stp_request_started_soft_reset_await_h2d_asserted_completion_enter, - }, - [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE] = { - .enter_state = scic_sds_stp_request_started_soft_reset_await_h2d_diagnostic_completion_enter, - }, - [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE] = { - .enter_state = scic_sds_stp_request_started_soft_reset_await_d2h_response_enter, - }, -}; - -enum sci_status scic_sds_stp_soft_reset_request_construct(struct scic_sds_request *sci_req) -{ - struct scic_sds_stp_request *stp_req = &sci_req->stp.req; - - scic_sds_stp_non_ncq_request_construct(sci_req); - - /* Build the STP task context structure */ - scu_stp_raw_request_construct_task_context(stp_req, sci_req->task_context_buffer); - - sci_base_state_machine_construct(&sci_req->started_substate_machine, - sci_req, - scic_sds_stp_request_started_soft_reset_substate_table, - SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE); - - return SCI_SUCCESS; -} diff --git a/drivers/scsi/isci/core/scic_sds_stp_request.h b/drivers/scsi/isci/core/scic_sds_stp_request.h deleted file mode 100644 index f5434f12ad06..000000000000 --- a/drivers/scsi/isci/core/scic_sds_stp_request.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SCIC_SDS_STP_REQUEST_T_ -#define _SCIC_SDS_STP_REQUEST_T_ - -#include -#include - -struct scic_sds_stp_request { - union { - u32 ncq; - - u32 udma; - - struct scic_sds_stp_pio_request { - /** - * Total transfer for the entire PIO request recorded at request constuction - * time. - * - * @todo Should we just decrement this value for each byte of data transitted - * or received to elemenate the current_transfer_bytes field? - */ - u32 total_transfer_bytes; - - /** - * Total number of bytes received/transmitted in data frames since the start - * of the IO request. At the end of the IO request this should equal the - * total_transfer_bytes. - */ - u32 current_transfer_bytes; - - /** - * The number of bytes requested in the in the PIO setup. - */ - u32 pio_transfer_bytes; - - /** - * PIO Setup ending status value to tell us if we need to wait for another FIS - * or if the transfer is complete. On the receipt of a D2H FIS this will be - * the status field of that FIS. - */ - u8 ending_status; - - /** - * On receipt of a D2H FIS this will be the ending error field if the - * ending_status has the SATA_STATUS_ERR bit set. - */ - u8 ending_error; - - struct scic_sds_request_pio_sgl { - struct scu_sgl_element_pair *sgl_pair; - u8 sgl_set; - u32 sgl_offset; - } request_current; - } pio; - - struct { - /** - * The number of bytes requested in the PIO setup before CDB data frame. - */ - u32 device_preferred_cdb_length; - } packet; - } type; -}; - -/** - * enum scic_sds_stp_request_started_udma_substates - This enumeration depicts - * the various sub-states associated with a SATA/STP UDMA protocol operation. - * - * - */ -enum scic_sds_stp_request_started_udma_substates { - SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE, - SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE, -}; - -/** - * enum scic_sds_stp_request_started_non_data_substates - This enumeration - * depicts the various sub-states associated with a SATA/STP non-data - * protocol operation. - * - * - */ -enum scic_sds_stp_request_started_non_data_substates { - SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE, - SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE, -}; - -/** - * enum scic_sds_stp_request_started_soft_reset_substates - THis enumeration - * depicts the various sub-states associated with a SATA/STP soft reset - * operation. - * - * - */ -enum scic_sds_stp_request_started_soft_reset_substates { - SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE, - SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE, - SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE, -}; - -u32 scic_sds_stp_request_get_object_size(void); - -enum sci_status scic_sds_stp_pio_request_construct( - struct scic_sds_request *scic_io_request, - bool copy_rx_frame); - -enum sci_status scic_sds_stp_udma_request_construct( - struct scic_sds_request *sci_req, - u32 transfer_length, - enum dma_data_direction dir); - -enum sci_status scic_sds_stp_non_data_request_construct( - struct scic_sds_request *sci_req); - -enum sci_status scic_sds_stp_soft_reset_request_construct( - struct scic_sds_request *sci_req); - -enum sci_status scic_sds_stp_ncq_request_construct( - struct scic_sds_request *sci_req, - u32 transfer_length, - enum dma_data_direction dir); - - -#endif /* _SCIC_SDS_STP_REQUEST_T_ */ diff --git a/drivers/scsi/isci/core/scic_task_request.h b/drivers/scsi/isci/core/scic_task_request.h deleted file mode 100644 index 790cee9b4af6..000000000000 --- a/drivers/scsi/isci/core/scic_task_request.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SCIC_TASK_REQUEST_H_ -#define _SCIC_TASK_REQUEST_H_ - -#include "isci.h" - -struct scic_sds_request; -struct scic_sds_remote_device; -struct scic_sds_controller; - - -enum sci_status scic_task_request_construct( - struct scic_sds_controller *scic_controller, - struct scic_sds_remote_device *scic_remote_device, - u16 io_tag, struct scic_sds_request *sci_req); - -/** - * scic_task_request_construct_ssp() - This method is called by the SCI user to - * construct all SCI Core SSP task management requests. Memory - * initialization and functionality common to all task request types is - * performed in this method. - * @scic_task_request: This parameter specifies the handle to the core task - * request object for which to construct a SATA specific task management - * request. - * - * Indicate if the controller successfully built the task request. SCI_SUCCESS - * This value is returned if the task request was successfully built. - */ -enum sci_status scic_task_request_construct_ssp( - struct scic_sds_request *scic_task_request); - -/** - * scic_task_request_construct_sata() - This method is called by the SCI user - * to construct all SCI Core SATA task management requests. Memory - * initialization and functionality common to all task request types is - * performed in this method. - * @scic_task_request_handle: This parameter specifies the handle to the core - * task request object for which to construct a SATA specific task - * management request. - * - * Indicate if the controller successfully built the task request. SCI_SUCCESS - * This value is returned if the task request was successfully built. - */ -enum sci_status scic_task_request_construct_sata( - struct scic_sds_request *scic_task_request_handle); - - - -#endif /* _SCIC_TASK_REQUEST_H_ */ - diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 71a0466d1c8e..e1930da08d4e 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -61,9 +61,7 @@ #include "probe_roms.h" #include "remote_device.h" #include "request.h" -#include "scic_io_request.h" #include "scic_sds_port_configuration_agent.h" -#include "sci_util.h" #include "scu_completion_codes.h" #include "scu_event_codes.h" #include "registers.h" diff --git a/drivers/scsi/isci/isci.h b/drivers/scsi/isci/isci.h index d288897b85fb..69826eac97b5 100644 --- a/drivers/scsi/isci/isci.h +++ b/drivers/scsi/isci/isci.h @@ -521,6 +521,25 @@ enum sci_task_status { }; +/** + * sci_swab32_cpy - convert between scsi and scu-hardware byte format + * @dest: receive the 4-byte endian swapped version of src + * @src: word aligned source buffer + * + * scu hardware handles SSP/SMP control, response, and unidentified + * frames in "big endian dword" order. Regardless of host endian this + * is always a swab32()-per-dword conversion of the standard definition, + * i.e. single byte fields swapped and multi-byte fields in little- + * endian + */ +static inline void sci_swab32_cpy(void *_dest, void *_src, ssize_t word_cnt) +{ + u32 *dest = _dest, *src = _src; + + while (--word_cnt >= 0) + dest[word_cnt] = swab32(src[word_cnt]); +} + extern unsigned char no_outbound_task_to; extern u16 ssp_max_occ_to; extern u16 stp_max_occ_to; diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c index f44fa20cad96..d4bf6d2d8c9b 100644 --- a/drivers/scsi/isci/port.c +++ b/drivers/scsi/isci/port.c @@ -55,7 +55,6 @@ #include #include "isci.h" -#include "scic_io_request.h" #include "scic_phy.h" #include "scic_sds_phy.h" #include "scic_port.h" diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index 00334b9ccd80..23390102514f 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c @@ -57,14 +57,11 @@ #include "port.h" #include "remote_device.h" #include "request.h" -#include "scic_io_request.h" #include "scic_phy.h" #include "scic_port.h" #include "scic_sds_phy.h" #include "scic_sds_port.h" #include "remote_node_context.h" -#include "scic_sds_request.h" -#include "sci_util.h" #include "scu_event_codes.h" #include "task.h" diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c index 5891f3d50177..35231e7407b1 100644 --- a/drivers/scsi/isci/remote_node_context.c +++ b/drivers/scsi/isci/remote_node_context.c @@ -58,7 +58,6 @@ #include "scic_sds_port.h" #include "remote_device.h" #include "remote_node_context.h" -#include "sci_util.h" #include "scu_event_codes.h" #include "scu_task_context.h" diff --git a/drivers/scsi/isci/remote_node_table.c b/drivers/scsi/isci/remote_node_table.c index 80f44c25f45f..6b9465a5a217 100644 --- a/drivers/scsi/isci/remote_node_table.c +++ b/drivers/scsi/isci/remote_node_table.c @@ -59,7 +59,6 @@ * * */ -#include "sci_util.h" #include "remote_node_table.h" #include "remote_node_context.h" diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index 4961ee347091..857ad067f11c 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -54,898 +54,1286 @@ */ #include "isci.h" -#include "scic_io_request.h" -#include "scic_task_request.h" #include "scic_port.h" #include "task.h" #include "request.h" #include "sata.h" #include "scu_completion_codes.h" -#include "scic_sds_request.h" #include "sas.h" -static enum sci_status isci_request_ssp_request_construct( - struct isci_request *request) -{ - enum sci_status status; +/** + * This method returns the sgl element pair for the specificed sgl_pair index. + * @sci_req: This parameter specifies the IO request for which to retrieve + * the Scatter-Gather List element pair. + * @sgl_pair_index: This parameter specifies the index into the SGL element + * pair to be retrieved. + * + * This method returns a pointer to an struct scu_sgl_element_pair. + */ +static struct scu_sgl_element_pair *scic_sds_request_get_sgl_element_pair( + struct scic_sds_request *sci_req, + u32 sgl_pair_index + ) { + struct scu_task_context *task_context; + + task_context = (struct scu_task_context *)sci_req->task_context_buffer; + + if (sgl_pair_index == 0) { + return &task_context->sgl_pair_ab; + } else if (sgl_pair_index == 1) { + return &task_context->sgl_pair_cd; + } - dev_dbg(&request->isci_host->pdev->dev, - "%s: request = %p\n", - __func__, - request); - status = scic_io_request_construct_basic_ssp(&request->sci); - return status; + return &sci_req->sg_table[sgl_pair_index - 2]; } -static enum sci_status isci_request_stp_request_construct( - struct isci_request *request) +/** + * This function will build the SGL list for an IO request. + * @sci_req: This parameter specifies the IO request for which to build + * the Scatter-Gather List. + * + */ +void scic_sds_request_build_sgl(struct scic_sds_request *sds_request) { - struct sas_task *task = isci_request_access_task(request); - enum sci_status status; - struct host_to_dev_fis *register_fis; - - dev_dbg(&request->isci_host->pdev->dev, - "%s: request = %p\n", - __func__, - request); + struct isci_request *isci_request = sci_req_to_ireq(sds_request); + struct isci_host *isci_host = isci_request->isci_host; + struct sas_task *task = isci_request_access_task(isci_request); + struct scatterlist *sg = NULL; + dma_addr_t dma_addr; + u32 sg_idx = 0; + struct scu_sgl_element_pair *scu_sg = NULL; + struct scu_sgl_element_pair *prev_sg = NULL; + + if (task->num_scatter > 0) { + sg = task->scatter; + + while (sg) { + scu_sg = scic_sds_request_get_sgl_element_pair( + sds_request, + sg_idx); + + SCU_SGL_COPY(scu_sg->A, sg); + + sg = sg_next(sg); + + if (sg) { + SCU_SGL_COPY(scu_sg->B, sg); + sg = sg_next(sg); + } else + SCU_SGL_ZERO(scu_sg->B); + + if (prev_sg) { + dma_addr = + scic_io_request_get_dma_addr( + sds_request, + scu_sg); + + prev_sg->next_pair_upper = + upper_32_bits(dma_addr); + prev_sg->next_pair_lower = + lower_32_bits(dma_addr); + } + + prev_sg = scu_sg; + sg_idx++; + } + } else { /* handle when no sg */ + scu_sg = scic_sds_request_get_sgl_element_pair(sds_request, + sg_idx); - /* Get the host_to_dev_fis from the core and copy - * the fis from the task into it. - */ - register_fis = isci_sata_task_to_fis_copy(task); + dma_addr = dma_map_single(&isci_host->pdev->dev, + task->scatter, + task->total_xfer_len, + task->data_dir); - status = scic_io_request_construct_basic_sata(&request->sci); + isci_request->zero_scatter_daddr = dma_addr; - /* Set the ncq tag in the fis, from the queue - * command in the task. - */ - if (isci_sata_is_task_ncq(task)) { + scu_sg->A.length = task->total_xfer_len; + scu_sg->A.address_upper = upper_32_bits(dma_addr); + scu_sg->A.address_lower = lower_32_bits(dma_addr); + } - isci_sata_set_ncq_tag( - register_fis, - task - ); + if (scu_sg) { + scu_sg->next_pair_upper = 0; + scu_sg->next_pair_lower = 0; } +} - return status; +static void scic_sds_ssp_io_request_assign_buffers(struct scic_sds_request *sci_req) +{ + if (sci_req->was_tag_assigned_by_user == false) + sci_req->task_context_buffer = &sci_req->tc; } -/* - * isci_smp_request_build() - This function builds the smp request. - * @ireq: This parameter points to the isci_request allocated in the - * request construct function. - * - * SCI_SUCCESS on successfull completion, or specific failure code. - */ -static enum sci_status isci_smp_request_build(struct isci_request *ireq) +static void scic_sds_io_request_build_ssp_command_iu(struct scic_sds_request *sci_req) { - enum sci_status status = SCI_FAILURE; + struct ssp_cmd_iu *cmd_iu; + struct isci_request *ireq = sci_req_to_ireq(sci_req); struct sas_task *task = isci_request_access_task(ireq); - struct scic_sds_request *sci_req = &ireq->sci; - dev_dbg(&ireq->isci_host->pdev->dev, - "%s: request = %p\n", __func__, ireq); + cmd_iu = &sci_req->ssp.cmd; - dev_dbg(&ireq->isci_host->pdev->dev, - "%s: smp_req len = %d\n", - __func__, - task->smp_task.smp_req.length); + memcpy(cmd_iu->LUN, task->ssp_task.LUN, 8); + cmd_iu->add_cdb_len = 0; + cmd_iu->_r_a = 0; + cmd_iu->_r_b = 0; + cmd_iu->en_fburst = 0; /* unsupported */ + cmd_iu->task_prio = task->ssp_task.task_prio; + cmd_iu->task_attr = task->ssp_task.task_attr; + cmd_iu->_r_c = 0; - /* copy the smp_command to the address; */ - sg_copy_to_buffer(&task->smp_task.smp_req, 1, - &sci_req->smp.cmd, - sizeof(struct smp_req)); + sci_swab32_cpy(&cmd_iu->cdb, task->ssp_task.cdb, + sizeof(task->ssp_task.cdb) / sizeof(u32)); +} - status = scic_io_request_construct_smp(sci_req); - if (status != SCI_SUCCESS) - dev_warn(&ireq->isci_host->pdev->dev, - "%s: failed with status = %d\n", - __func__, - status); +static void scic_sds_task_request_build_ssp_task_iu(struct scic_sds_request *sci_req) +{ + struct ssp_task_iu *task_iu; + struct isci_request *ireq = sci_req_to_ireq(sci_req); + struct sas_task *task = isci_request_access_task(ireq); + struct isci_tmf *isci_tmf = isci_request_access_tmf(ireq); - return status; + task_iu = &sci_req->ssp.tmf; + + memset(task_iu, 0, sizeof(struct ssp_task_iu)); + + memcpy(task_iu->LUN, task->ssp_task.LUN, 8); + + task_iu->task_func = isci_tmf->tmf_code; + task_iu->task_tag = + (ireq->ttype == tmf_task) ? + isci_tmf->io_tag : + SCI_CONTROLLER_INVALID_IO_TAG; } /** - * isci_io_request_build() - This function builds the io request object. - * @isci_host: This parameter specifies the ISCI host object - * @request: This parameter points to the isci_request object allocated in the - * request construct function. - * @sci_device: This parameter is the handle for the sci core's remote device - * object that is the destination for this request. + * This method is will fill in the SCU Task Context for any type of SSP request. + * @sci_req: + * @task_context: * - * SCI_SUCCESS on successfull completion, or specific failure code. */ -static enum sci_status isci_io_request_build( - struct isci_host *isci_host, - struct isci_request *request, - struct isci_remote_device *isci_device) +static void scu_ssp_reqeust_construct_task_context( + struct scic_sds_request *sds_request, + struct scu_task_context *task_context) { - enum sci_status status = SCI_SUCCESS; - struct sas_task *task = isci_request_access_task(request); - struct scic_sds_remote_device *sci_device = &isci_device->sci; + dma_addr_t dma_addr; + struct scic_sds_controller *controller; + struct scic_sds_remote_device *target_device; + struct scic_sds_port *target_port; + + controller = scic_sds_request_get_controller(sds_request); + target_device = scic_sds_request_get_device(sds_request); + target_port = scic_sds_request_get_port(sds_request); + + /* Fill in the TC with the its required data */ + task_context->abort = 0; + task_context->priority = 0; + task_context->initiator_request = 1; + task_context->connection_rate = target_device->connection_rate; + task_context->protocol_engine_index = + scic_sds_controller_get_protocol_engine_group(controller); + task_context->logical_port_index = + scic_sds_port_get_index(target_port); + task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP; + task_context->valid = SCU_TASK_CONTEXT_VALID; + task_context->context_type = SCU_TASK_CONTEXT_TYPE; + + task_context->remote_node_index = + scic_sds_remote_device_get_index(sds_request->target_device); + task_context->command_code = 0; + + task_context->link_layer_control = 0; + task_context->do_not_dma_ssp_good_response = 1; + task_context->strict_ordering = 0; + task_context->control_frame = 0; + task_context->timeout_enable = 0; + task_context->block_guard_enable = 0; + + task_context->address_modifier = 0; + + /* task_context->type.ssp.tag = sci_req->io_tag; */ + task_context->task_phase = 0x01; + + if (sds_request->was_tag_assigned_by_user) { + /* + * Build the task context now since we have already read + * the data + */ + sds_request->post_context = + (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | + (scic_sds_controller_get_protocol_engine_group( + controller) << + SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | + (scic_sds_port_get_index(target_port) << + SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) | + scic_sds_io_tag_get_index(sds_request->io_tag)); + } else { + /* + * Build the task context now since we have already read + * the data + * + * I/O tag index is not assigned because we have to wait + * until we get a TCi + */ + sds_request->post_context = + (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | + (scic_sds_controller_get_protocol_engine_group( + owning_controller) << + SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | + (scic_sds_port_get_index(target_port) << + SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)); + } - dev_dbg(&isci_host->pdev->dev, - "%s: isci_device = 0x%p; request = %p, " - "num_scatter = %d\n", - __func__, - isci_device, - request, - task->num_scatter); + /* + * Copy the physical address for the command buffer to the + * SCU Task Context + */ + dma_addr = scic_io_request_get_dma_addr(sds_request, + &sds_request->ssp.cmd); - /* map the sgl addresses, if present. - * libata does the mapping for sata devices - * before we get the request. + task_context->command_iu_upper = upper_32_bits(dma_addr); + task_context->command_iu_lower = lower_32_bits(dma_addr); + + /* + * Copy the physical address for the response buffer to the + * SCU Task Context */ - if (task->num_scatter && - !sas_protocol_ata(task->task_proto) && - !(SAS_PROTOCOL_SMP & task->task_proto)) { + dma_addr = scic_io_request_get_dma_addr(sds_request, + &sds_request->ssp.rsp); - request->num_sg_entries = dma_map_sg( - &isci_host->pdev->dev, - task->scatter, - task->num_scatter, - task->data_dir - ); + task_context->response_iu_upper = upper_32_bits(dma_addr); + task_context->response_iu_lower = lower_32_bits(dma_addr); +} - if (request->num_sg_entries == 0) - return SCI_FAILURE_INSUFFICIENT_RESOURCES; - } +/** + * This method is will fill in the SCU Task Context for a SSP IO request. + * @sci_req: + * + */ +static void scu_ssp_io_request_construct_task_context( + struct scic_sds_request *sci_req, + enum dma_data_direction dir, + u32 len) +{ + struct scu_task_context *task_context; - /* build the common request object. For now, - * we will let the core allocate the IO tag. - */ - status = scic_io_request_construct(&isci_host->sci, sci_device, - SCI_CONTROLLER_INVALID_IO_TAG, - &request->sci); + task_context = scic_sds_request_get_task_context(sci_req); - if (status != SCI_SUCCESS) { - dev_warn(&isci_host->pdev->dev, - "%s: failed request construct\n", - __func__); - return SCI_FAILURE; - } + scu_ssp_reqeust_construct_task_context(sci_req, task_context); - switch (task->task_proto) { - case SAS_PROTOCOL_SMP: - status = isci_smp_request_build(request); - break; - case SAS_PROTOCOL_SSP: - status = isci_request_ssp_request_construct(request); + task_context->ssp_command_iu_length = + sizeof(struct ssp_cmd_iu) / sizeof(u32); + task_context->type.ssp.frame_type = SSP_COMMAND; + + switch (dir) { + case DMA_FROM_DEVICE: + case DMA_NONE: + default: + task_context->task_type = SCU_TASK_TYPE_IOREAD; break; - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: - status = isci_request_stp_request_construct(request); + case DMA_TO_DEVICE: + task_context->task_type = SCU_TASK_TYPE_IOWRITE; break; - default: - dev_warn(&isci_host->pdev->dev, - "%s: unknown protocol\n", __func__); - return SCI_FAILURE; } - return SCI_SUCCESS; + task_context->transfer_length_bytes = len; + + if (task_context->transfer_length_bytes > 0) + scic_sds_request_build_sgl(sci_req); } +static void scic_sds_ssp_task_request_assign_buffers(struct scic_sds_request *sci_req) +{ + if (sci_req->was_tag_assigned_by_user == false) + sci_req->task_context_buffer = &sci_req->tc; +} /** - * isci_request_alloc_core() - This function gets the request object from the - * isci_host dma cache. - * @isci_host: This parameter specifies the ISCI host object - * @isci_request: This parameter will contain the pointer to the new - * isci_request object. - * @isci_device: This parameter is the pointer to the isci remote device object - * that is the destination for this request. - * @gfp_flags: This parameter specifies the os allocation flags. + * This method will fill in the SCU Task Context for a SSP Task request. The + * following important settings are utilized: -# priority == + * SCU_TASK_PRIORITY_HIGH. This ensures that the task request is issued + * ahead of other task destined for the same Remote Node. -# task_type == + * SCU_TASK_TYPE_IOREAD. This simply indicates that a normal request type + * (i.e. non-raw frame) is being utilized to perform task management. -# + * control_frame == 1. This ensures that the proper endianess is set so + * that the bytes are transmitted in the right order for a task frame. + * @sci_req: This parameter specifies the task request object being + * constructed. * - * SCI_SUCCESS on successfull completion, or specific failure code. */ -static int isci_request_alloc_core( - struct isci_host *isci_host, - struct isci_request **isci_request, - struct isci_remote_device *isci_device, - gfp_t gfp_flags) +static void scu_ssp_task_request_construct_task_context( + struct scic_sds_request *sci_req) { - int ret = 0; - dma_addr_t handle; - struct isci_request *request; - - - /* get pointer to dma memory. This actually points - * to both the isci_remote_device object and the - * sci object. The isci object is at the beginning - * of the memory allocated here. - */ - request = dma_pool_alloc(isci_host->dma_pool, gfp_flags, &handle); - if (!request) { - dev_warn(&isci_host->pdev->dev, - "%s: dma_pool_alloc returned NULL\n", __func__); - return -ENOMEM; - } - - /* initialize the request object. */ - spin_lock_init(&request->state_lock); - request->request_daddr = handle; - request->isci_host = isci_host; - request->isci_device = isci_device; - request->io_request_completion = NULL; - request->terminated = false; - - request->num_sg_entries = 0; - - request->complete_in_target = false; + struct scu_task_context *task_context; - INIT_LIST_HEAD(&request->completed_node); - INIT_LIST_HEAD(&request->dev_node); + task_context = scic_sds_request_get_task_context(sci_req); - *isci_request = request; - isci_request_change_state(request, allocated); + scu_ssp_reqeust_construct_task_context(sci_req, task_context); - return ret; + task_context->control_frame = 1; + task_context->priority = SCU_TASK_PRIORITY_HIGH; + task_context->task_type = SCU_TASK_TYPE_RAW_FRAME; + task_context->transfer_length_bytes = 0; + task_context->type.ssp.frame_type = SSP_TASK; + task_context->ssp_command_iu_length = + sizeof(struct ssp_task_iu) / sizeof(u32); } -static int isci_request_alloc_io( - struct isci_host *isci_host, - struct sas_task *task, - struct isci_request **isci_request, - struct isci_remote_device *isci_device, - gfp_t gfp_flags) -{ - int retval = isci_request_alloc_core(isci_host, isci_request, - isci_device, gfp_flags); - if (!retval) { - (*isci_request)->ttype_ptr.io_task_ptr = task; - (*isci_request)->ttype = io_task; +/** + * This method constructs the SSP Command IU data for this ssp passthrough + * comand request object. + * @sci_req: This parameter specifies the request object for which the SSP + * command information unit is being built. + * + * enum sci_status, returns invalid parameter is cdb > 16 + */ - task->lldd_task = *isci_request; - } - return retval; -} /** - * isci_request_alloc_tmf() - This function gets the request object from the - * isci_host dma cache and initializes the relevant fields as a sas_task. - * @isci_host: This parameter specifies the ISCI host object - * @sas_task: This parameter is the task struct from the upper layer driver. - * @isci_request: This parameter will contain the pointer to the new - * isci_request object. - * @isci_device: This parameter is the pointer to the isci remote device object - * that is the destination for this request. - * @gfp_flags: This parameter specifies the os allocation flags. + * This method constructs the SATA request object. + * @sci_req: + * @sat_protocol: + * @transfer_length: + * @data_direction: + * @copy_rx_frame: * - * SCI_SUCCESS on successfull completion, or specific failure code. + * enum sci_status */ -int isci_request_alloc_tmf( - struct isci_host *isci_host, - struct isci_tmf *isci_tmf, - struct isci_request **isci_request, - struct isci_remote_device *isci_device, - gfp_t gfp_flags) +static enum sci_status +scic_io_request_construct_sata(struct scic_sds_request *sci_req, + u32 len, + enum dma_data_direction dir, + bool copy) { - int retval = isci_request_alloc_core(isci_host, isci_request, - isci_device, gfp_flags); + enum sci_status status = SCI_SUCCESS; + struct isci_request *ireq = sci_req_to_ireq(sci_req); + struct sas_task *task = isci_request_access_task(ireq); - if (!retval) { + /* check for management protocols */ + if (ireq->ttype == tmf_task) { + struct isci_tmf *tmf = isci_request_access_tmf(ireq); - (*isci_request)->ttype_ptr.tmf_task_ptr = isci_tmf; - (*isci_request)->ttype = tmf_task; + if (tmf->tmf_code == isci_tmf_sata_srst_high || + tmf->tmf_code == isci_tmf_sata_srst_low) + return scic_sds_stp_soft_reset_request_construct(sci_req); + else { + dev_err(scic_to_dev(sci_req->owning_controller), + "%s: Request 0x%p received un-handled SAT " + "management protocol 0x%x.\n", + __func__, sci_req, tmf->tmf_code); + + return SCI_FAILURE; + } } - return retval; -} -/** - * isci_request_execute() - This function allocates the isci_request object, - * all fills in some common fields. - * @isci_host: This parameter specifies the ISCI host object - * @sas_task: This parameter is the task struct from the upper layer driver. - * @isci_request: This parameter will contain the pointer to the new - * isci_request object. - * @gfp_flags: This parameter specifies the os allocation flags. - * - * SCI_SUCCESS on successfull completion, or specific failure code. - */ -int isci_request_execute( - struct isci_host *isci_host, - struct sas_task *task, - struct isci_request **isci_request, - gfp_t gfp_flags) + if (!sas_protocol_ata(task->task_proto)) { + dev_err(scic_to_dev(sci_req->owning_controller), + "%s: Non-ATA protocol in SATA path: 0x%x\n", + __func__, + task->task_proto); + return SCI_FAILURE; + + } + + /* non data */ + if (task->data_dir == DMA_NONE) + return scic_sds_stp_non_data_request_construct(sci_req); + + /* NCQ */ + if (task->ata_task.use_ncq) + return scic_sds_stp_ncq_request_construct(sci_req, len, dir); + + /* DMA */ + if (task->ata_task.dma_xfer) + return scic_sds_stp_udma_request_construct(sci_req, len, dir); + else /* PIO */ + return scic_sds_stp_pio_request_construct(sci_req, copy); + + return status; +} + +static enum sci_status scic_io_request_construct_basic_ssp(struct scic_sds_request *sci_req) { - int ret = 0; - struct scic_sds_remote_device *sci_device; - enum sci_status status = SCI_FAILURE_UNSUPPORTED_PROTOCOL; - struct isci_remote_device *isci_device; - struct isci_request *request; - unsigned long flags; + struct isci_request *ireq = sci_req_to_ireq(sci_req); + struct sas_task *task = isci_request_access_task(ireq); - isci_device = task->dev->lldd_dev; - sci_device = &isci_device->sci; + sci_req->protocol = SCIC_SSP_PROTOCOL; - /* do common allocation and init of request object. */ - ret = isci_request_alloc_io( - isci_host, - task, - &request, - isci_device, - gfp_flags - ); + scu_ssp_io_request_construct_task_context(sci_req, + task->data_dir, + task->total_xfer_len); - if (ret) - goto out; + scic_sds_io_request_build_ssp_command_iu(sci_req); - status = isci_io_request_build(isci_host, request, isci_device); - if (status != SCI_SUCCESS) { - dev_warn(&isci_host->pdev->dev, - "%s: request_construct failed - status = 0x%x\n", - __func__, - status); - goto out; - } + sci_base_state_machine_change_state( + &sci_req->state_machine, + SCI_BASE_REQUEST_STATE_CONSTRUCTED); - spin_lock_irqsave(&isci_host->scic_lock, flags); + return SCI_SUCCESS; +} - /* send the request, let the core assign the IO TAG. */ - status = scic_controller_start_io(&isci_host->sci, sci_device, - &request->sci, - SCI_CONTROLLER_INVALID_IO_TAG); - if (status != SCI_SUCCESS && - status != SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) { - dev_warn(&isci_host->pdev->dev, - "%s: failed request start (0x%x)\n", - __func__, status); - spin_unlock_irqrestore(&isci_host->scic_lock, flags); - goto out; - } +enum sci_status scic_task_request_construct_ssp( + struct scic_sds_request *sci_req) +{ + /* Construct the SSP Task SCU Task Context */ + scu_ssp_task_request_construct_task_context(sci_req); - /* Either I/O started OK, or the core has signaled that - * the device needs a target reset. - * - * In either case, hold onto the I/O for later. - * - * Update it's status and add it to the list in the - * remote device object. - */ - isci_request_change_state(request, started); - list_add(&request->dev_node, &isci_device->reqs_in_process); + /* Fill in the SSP Task IU */ + scic_sds_task_request_build_ssp_task_iu(sci_req); - if (status == SCI_SUCCESS) { - /* Save the tag for possible task mgmt later. */ - request->io_tag = scic_io_request_get_io_tag(&request->sci); - } else { - /* The request did not really start in the - * hardware, so clear the request handle - * here so no terminations will be done. - */ - request->terminated = true; - } - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + sci_base_state_machine_change_state(&sci_req->state_machine, + SCI_BASE_REQUEST_STATE_CONSTRUCTED); - if (status == - SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) { - /* Signal libsas that we need the SCSI error - * handler thread to work on this I/O and that - * we want a device reset. - */ - spin_lock_irqsave(&task->task_state_lock, flags); - task->task_state_flags |= SAS_TASK_NEED_DEV_RESET; - spin_unlock_irqrestore(&task->task_state_lock, flags); + return SCI_SUCCESS; +} - /* Cause this task to be scheduled in the SCSI error - * handler thread. - */ - isci_execpath_callback(isci_host, task, - sas_task_abort); - /* Change the status, since we are holding - * the I/O until it is managed by the SCSI - * error handler. - */ - status = SCI_SUCCESS; - } +static enum sci_status scic_io_request_construct_basic_sata(struct scic_sds_request *sci_req) +{ + enum sci_status status; + struct scic_sds_stp_request *stp_req; + bool copy = false; + struct isci_request *isci_request = sci_req_to_ireq(sci_req); + struct sas_task *task = isci_request_access_task(isci_request); - out: - if (status != SCI_SUCCESS) { - /* release dma memory on failure. */ - isci_request_free(isci_host, request); - request = NULL; - ret = SCI_FAILURE; - } + stp_req = &sci_req->stp.req; + sci_req->protocol = SCIC_STP_PROTOCOL; - *isci_request = request; - return ret; + copy = (task->data_dir == DMA_NONE) ? false : true; + + status = scic_io_request_construct_sata(sci_req, + task->total_xfer_len, + task->data_dir, + copy); + + if (status == SCI_SUCCESS) + sci_base_state_machine_change_state(&sci_req->state_machine, + SCI_BASE_REQUEST_STATE_CONSTRUCTED); + + return status; } +enum sci_status scic_task_request_construct_sata(struct scic_sds_request *sci_req) +{ + enum sci_status status = SCI_SUCCESS; + struct isci_request *ireq = sci_req_to_ireq(sci_req); + + /* check for management protocols */ + if (ireq->ttype == tmf_task) { + struct isci_tmf *tmf = isci_request_access_tmf(ireq); + + if (tmf->tmf_code == isci_tmf_sata_srst_high || + tmf->tmf_code == isci_tmf_sata_srst_low) { + status = scic_sds_stp_soft_reset_request_construct(sci_req); + } else { + dev_err(scic_to_dev(sci_req->owning_controller), + "%s: Request 0x%p received un-handled SAT " + "Protocol 0x%x.\n", + __func__, sci_req, tmf->tmf_code); + + return SCI_FAILURE; + } + } + + if (status == SCI_SUCCESS) + sci_base_state_machine_change_state( + &sci_req->state_machine, + SCI_BASE_REQUEST_STATE_CONSTRUCTED); + + return status; +} + /** - * isci_request_process_response_iu() - This function sets the status and - * response iu, in the task struct, from the request object for the upper - * layer driver. - * @sas_task: This parameter is the task struct from the upper layer driver. - * @resp_iu: This parameter points to the response iu of the completed request. - * @dev: This parameter specifies the linux device struct. - * - * none. + * sci_req_tx_bytes - bytes transferred when reply underruns request + * @sci_req: request that was terminated early */ -static void isci_request_process_response_iu( - struct sas_task *task, - struct ssp_response_iu *resp_iu, - struct device *dev) +#define SCU_TASK_CONTEXT_SRAM 0x200000 +static u32 sci_req_tx_bytes(struct scic_sds_request *sci_req) { - dev_dbg(dev, - "%s: resp_iu = %p " - "resp_iu->status = 0x%x,\nresp_iu->datapres = %d " - "resp_iu->response_data_len = %x, " - "resp_iu->sense_data_len = %x\nrepsonse data: ", + struct scic_sds_controller *scic = sci_req->owning_controller; + u32 ret_val = 0; + + if (readl(&scic->smu_registers->address_modifier) == 0) { + void __iomem *scu_reg_base = scic->scu_registers; + + /* get the bytes of data from the Address == BAR1 + 20002Ch + (256*TCi) where + * BAR1 is the scu_registers + * 0x20002C = 0x200000 + 0x2c + * = start of task context SRAM + offset of (type.ssp.data_offset) + * TCi is the io_tag of struct scic_sds_request + */ + ret_val = readl(scu_reg_base + + (SCU_TASK_CONTEXT_SRAM + offsetof(struct scu_task_context, type.ssp.data_offset)) + + ((sizeof(struct scu_task_context)) * scic_sds_io_tag_get_index(sci_req->io_tag))); + } + + return ret_val; +} + +enum sci_status +scic_sds_request_start(struct scic_sds_request *request) +{ + if (request->device_sequence != + scic_sds_remote_device_get_sequence(request->target_device)) + return SCI_FAILURE; + + if (request->state_handlers->start_handler) + return request->state_handlers->start_handler(request); + + dev_warn(scic_to_dev(request->owning_controller), + "%s: SCIC IO Request requested to start while in wrong " + "state %d\n", + __func__, + sci_base_state_machine_get_state(&request->state_machine)); + + return SCI_FAILURE_INVALID_STATE; +} + +enum sci_status +scic_sds_io_request_terminate(struct scic_sds_request *request) +{ + if (request->state_handlers->abort_handler) + return request->state_handlers->abort_handler(request); + + dev_warn(scic_to_dev(request->owning_controller), + "%s: SCIC IO Request requested to abort while in wrong " + "state %d\n", __func__, - resp_iu, - resp_iu->status, - resp_iu->datapres, - resp_iu->response_data_len, - resp_iu->sense_data_len); + sci_base_state_machine_get_state(&request->state_machine)); - task->task_status.stat = resp_iu->status; + return SCI_FAILURE_INVALID_STATE; +} - /* libsas updates the task status fields based on the response iu. */ - sas_ssp_task_response(dev, task, resp_iu); +enum sci_status scic_sds_io_request_event_handler( + struct scic_sds_request *request, + u32 event_code) +{ + if (request->state_handlers->event_handler) + return request->state_handlers->event_handler(request, event_code); + + dev_warn(scic_to_dev(request->owning_controller), + "%s: SCIC IO Request given event code notification %x while " + "in wrong state %d\n", + __func__, + event_code, + sci_base_state_machine_get_state(&request->state_machine)); + + return SCI_FAILURE_INVALID_STATE; } /** - * isci_request_set_open_reject_status() - This function prepares the I/O - * completion for OPEN_REJECT conditions. - * @request: This parameter is the completed isci_request object. - * @response_ptr: This parameter specifies the service response for the I/O. - * @status_ptr: This parameter specifies the exec status for the I/O. - * @complete_to_host_ptr: This parameter specifies the action to be taken by - * the LLDD with respect to completing this request or forcing an abort - * condition on the I/O. - * @open_rej_reason: This parameter specifies the encoded reason for the - * abandon-class reject. * - * none. + * @sci_req: The SCIC_SDS_IO_REQUEST_T object for which the start + * operation is to be executed. + * @frame_index: The frame index returned by the hardware for the reqeust + * object. + * + * This method invokes the core state frame handler for the + * SCIC_SDS_IO_REQUEST_T object. enum sci_status */ -static void 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 isci_completion_selection *complete_to_host_ptr, - enum sas_open_rej_reason open_rej_reason) +enum sci_status scic_sds_io_request_frame_handler( + struct scic_sds_request *request, + u32 frame_index) { - /* Task in the target is done. */ - request->complete_in_target = true; - *response_ptr = SAS_TASK_UNDELIVERED; - *status_ptr = SAS_OPEN_REJECT; - *complete_to_host_ptr = isci_perform_normal_io_completion; - task->task_status.open_rej_reason = open_rej_reason; + if (request->state_handlers->frame_handler) + return request->state_handlers->frame_handler(request, frame_index); + + dev_warn(scic_to_dev(request->owning_controller), + "%s: SCIC IO Request given unexpected frame %x while in " + "state %d\n", + __func__, + frame_index, + sci_base_state_machine_get_state(&request->state_machine)); + + scic_sds_controller_release_frame(request->owning_controller, frame_index); + return SCI_FAILURE_INVALID_STATE; } -/** - * isci_request_handle_controller_specific_errors() - This function decodes - * controller-specific I/O completion error conditions. - * @request: This parameter is the completed isci_request object. - * @response_ptr: This parameter specifies the service response for the I/O. - * @status_ptr: This parameter specifies the exec status for the I/O. - * @complete_to_host_ptr: This parameter specifies the action to be taken by - * the LLDD with respect to completing this request or forcing an abort - * condition on the I/O. - * - * none. +/* + * This function copies response data for requests returning response data + * instead of sense data. + * @sci_req: This parameter specifies the request object for which to copy + * the response data. */ -static void isci_request_handle_controller_specific_errors( - struct isci_remote_device *isci_device, - struct isci_request *request, - struct sas_task *task, - enum service_response *response_ptr, - enum exec_status *status_ptr, - enum isci_completion_selection *complete_to_host_ptr) +void scic_sds_io_request_copy_response(struct scic_sds_request *sci_req) { - unsigned int cstatus; + void *resp_buf; + u32 len; + struct ssp_response_iu *ssp_response; + struct isci_request *ireq = sci_req_to_ireq(sci_req); + struct isci_tmf *isci_tmf = isci_request_access_tmf(ireq); - cstatus = scic_request_get_controller_status(&request->sci); + ssp_response = &sci_req->ssp.rsp; - dev_dbg(&request->isci_host->pdev->dev, - "%s: %p SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR " - "- controller status = 0x%x\n", - __func__, request, cstatus); + resp_buf = &isci_tmf->resp.resp_iu; - /* Decode the controller-specific errors; most - * important is to recognize those conditions in which - * the target may still have a task outstanding that - * must be aborted. - * - * Note that there are SCU completion codes being - * named in the decode below for which SCIC has already - * done work to handle them in a way other than as - * a controller-specific completion code; these are left - * in the decode below for completeness sake. - */ - switch (cstatus) { - case SCU_TASK_DONE_DMASETUP_DIRERR: - /* Also SCU_TASK_DONE_SMP_FRM_TYPE_ERR: */ - case SCU_TASK_DONE_XFERCNT_ERR: - /* Also SCU_TASK_DONE_SMP_UFI_ERR: */ - if (task->task_proto == SAS_PROTOCOL_SMP) { - /* SCU_TASK_DONE_SMP_UFI_ERR == Task Done. */ - *response_ptr = SAS_TASK_COMPLETE; + len = min_t(u32, + SSP_RESP_IU_MAX_SIZE, + be32_to_cpu(ssp_response->response_data_len)); - /* See if the device has been/is being stopped. Note - * that we ignore the quiesce state, since we are - * concerned about the actual device state. - */ - if ((isci_device->status == isci_stopping) || - (isci_device->status == isci_stopped)) - *status_ptr = SAS_DEVICE_UNKNOWN; - else - *status_ptr = SAS_ABORTED_TASK; + memcpy(resp_buf, ssp_response->resp_data, len); +} - request->complete_in_target = true; +/* + * This method implements the action taken when a constructed + * SCIC_SDS_IO_REQUEST_T object receives a scic_sds_request_start() request. + * This method will, if necessary, allocate a TCi for the io request object and + * then will, if necessary, copy the constructed TC data into the actual TC + * buffer. If everything is successful the post context field is updated with + * the TCi so the controller can post the request to the hardware. enum sci_status + * SCI_SUCCESS SCI_FAILURE_INSUFFICIENT_RESOURCES + */ +static enum sci_status scic_sds_request_constructed_state_start_handler( + struct scic_sds_request *request) +{ + struct scu_task_context *task_context; - *complete_to_host_ptr = - isci_perform_normal_io_completion; - } else { - /* Task in the target is not done. */ - *response_ptr = SAS_TASK_UNDELIVERED; + if (request->io_tag == SCI_CONTROLLER_INVALID_IO_TAG) { + request->io_tag = + scic_controller_allocate_io_tag(request->owning_controller); + } - if ((isci_device->status == isci_stopping) || - (isci_device->status == isci_stopped)) - *status_ptr = SAS_DEVICE_UNKNOWN; - else - *status_ptr = SAM_STAT_TASK_ABORTED; + /* Record the IO Tag in the request */ + if (request->io_tag != SCI_CONTROLLER_INVALID_IO_TAG) { + task_context = request->task_context_buffer; - request->complete_in_target = false; + task_context->task_index = scic_sds_io_tag_get_index(request->io_tag); - *complete_to_host_ptr = - isci_perform_error_io_completion; - } + switch (task_context->protocol_type) { + case SCU_TASK_CONTEXT_PROTOCOL_SMP: + case SCU_TASK_CONTEXT_PROTOCOL_SSP: + /* SSP/SMP Frame */ + task_context->type.ssp.tag = request->io_tag; + task_context->type.ssp.target_port_transfer_tag = 0xFFFF; + break; - break; + case SCU_TASK_CONTEXT_PROTOCOL_STP: + /* + * STP/SATA Frame + * task_context->type.stp.ncq_tag = request->ncq_tag; */ + break; - case SCU_TASK_DONE_CRC_ERR: - case SCU_TASK_DONE_NAK_CMD_ERR: - case SCU_TASK_DONE_EXCESS_DATA: - case SCU_TASK_DONE_UNEXP_FIS: - /* Also SCU_TASK_DONE_UNEXP_RESP: */ - case SCU_TASK_DONE_VIIT_ENTRY_NV: /* TODO - conditions? */ - case SCU_TASK_DONE_IIT_ENTRY_NV: /* TODO - conditions? */ - case SCU_TASK_DONE_RNCNV_OUTBOUND: /* TODO - conditions? */ - /* These are conditions in which the target - * has completed the task, so that no cleanup - * is necessary. - */ - *response_ptr = SAS_TASK_COMPLETE; + case SCU_TASK_CONTEXT_PROTOCOL_NONE: + /* / @todo When do we set no protocol type? */ + break; - /* See if the device has been/is being stopped. Note - * that we ignore the quiesce state, since we are - * concerned about the actual device state. - */ - if ((isci_device->status == isci_stopping) || - (isci_device->status == isci_stopped)) - *status_ptr = SAS_DEVICE_UNKNOWN; - else - *status_ptr = SAS_ABORTED_TASK; + default: + /* This should never happen since we build the IO requests */ + break; + } - request->complete_in_target = true; + /* + * Check to see if we need to copy the task context buffer + * or have been building into the task context buffer */ + if (request->was_tag_assigned_by_user == false) { + scic_sds_controller_copy_task_context( + request->owning_controller, request); + } - *complete_to_host_ptr = isci_perform_normal_io_completion; - break; + /* Add to the post_context the io tag value */ + request->post_context |= scic_sds_io_tag_get_index(request->io_tag); + /* Everything is good go ahead and change state */ + sci_base_state_machine_change_state(&request->state_machine, + SCI_BASE_REQUEST_STATE_STARTED); - /* Note that the only open reject completion codes seen here will be - * abandon-class codes; all others are automatically retried in the SCU. - */ - case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION: + return SCI_SUCCESS; + } - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_WRONG_DEST); - break; + return SCI_FAILURE_INSUFFICIENT_RESOURCES; +} - case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION: +/* + * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T + * object receives a scic_sds_request_terminate() request. Since the request + * has not yet been posted to the hardware the request transitions to the + * completed state. enum sci_status SCI_SUCCESS + */ +static enum sci_status scic_sds_request_constructed_state_abort_handler( + struct scic_sds_request *request) +{ + /* + * This request has been terminated by the user make sure that the correct + * status code is returned */ + scic_sds_request_set_status(request, + SCU_TASK_DONE_TASK_ABORT, + SCI_FAILURE_IO_TERMINATED); + + sci_base_state_machine_change_state(&request->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + return SCI_SUCCESS; +} - /* Note - the return of AB0 will change when - * libsas implements detection of zone violations. - */ - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_RESV_AB0); - break; +/* + * ***************************************************************************** + * * STARTED STATE HANDLERS + * ***************************************************************************** */ - case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1: +/* + * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T + * object receives a scic_sds_request_terminate() request. Since the request + * has been posted to the hardware the io request state is changed to the + * aborting state. enum sci_status SCI_SUCCESS + */ +enum sci_status scic_sds_request_started_state_abort_handler( + struct scic_sds_request *request) +{ + if (request->has_started_substate_machine) + sci_base_state_machine_stop(&request->started_substate_machine); - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_RESV_AB1); - break; + sci_base_state_machine_change_state(&request->state_machine, + SCI_BASE_REQUEST_STATE_ABORTING); + return SCI_SUCCESS; +} - case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2: +/* + * scic_sds_request_started_state_tc_completion_handler() - This method process + * TC (task context) completions for normal IO request (i.e. Task/Abort + * Completions of type 0). This method will update the + * SCIC_SDS_IO_REQUEST_T::status field. + * @sci_req: This parameter specifies the request for which a completion + * occurred. + * @completion_code: This parameter specifies the completion code received from + * the SCU. + * + */ +static enum sci_status +scic_sds_request_started_state_tc_completion_handler(struct scic_sds_request *sci_req, + u32 completion_code) +{ + u8 datapres; + struct ssp_response_iu *resp_iu; - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_RESV_AB2); + /* + * TODO: Any SDMA return code of other than 0 is bad + * decode 0x003C0000 to determine SDMA status + */ + switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): + scic_sds_request_set_status(sci_req, + SCU_TASK_DONE_GOOD, + SCI_SUCCESS); break; - case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3: + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_EARLY_RESP): + { + /* + * There are times when the SCU hardware will return an early + * response because the io request specified more data than is + * returned by the target device (mode pages, inquiry data, + * etc.). We must check the response stats to see if this is + * truly a failed request or a good request that just got + * completed early. + */ + struct ssp_response_iu *resp = &sci_req->ssp.rsp; + ssize_t word_cnt = SSP_RESP_IU_MAX_SIZE / sizeof(u32); + + sci_swab32_cpy(&sci_req->ssp.rsp, + &sci_req->ssp.rsp, + word_cnt); + + if (resp->status == 0) { + scic_sds_request_set_status( + sci_req, + SCU_TASK_DONE_GOOD, + SCI_SUCCESS_IO_DONE_EARLY); + } else { + scic_sds_request_set_status( + sci_req, + SCU_TASK_DONE_CHECK_RESPONSE, + SCI_FAILURE_IO_RESPONSE_VALID); + } + } + break; - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_RESV_AB3); - break; + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CHECK_RESPONSE): + { + ssize_t word_cnt = SSP_RESP_IU_MAX_SIZE / sizeof(u32); - case SCU_TASK_OPEN_REJECT_BAD_DESTINATION: + sci_swab32_cpy(&sci_req->ssp.rsp, + &sci_req->ssp.rsp, + word_cnt); - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_BAD_DEST); + scic_sds_request_set_status(sci_req, + SCU_TASK_DONE_CHECK_RESPONSE, + SCI_FAILURE_IO_RESPONSE_VALID); break; + } - case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY: - - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_STP_NORES); + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_RESP_LEN_ERR): + /* + * / @todo With TASK_DONE_RESP_LEN_ERR is the response frame + * guaranteed to be received before this completion status is + * posted? + */ + resp_iu = &sci_req->ssp.rsp; + datapres = resp_iu->datapres; + + if ((datapres == 0x01) || (datapres == 0x02)) { + scic_sds_request_set_status( + sci_req, + SCU_TASK_DONE_CHECK_RESPONSE, + SCI_FAILURE_IO_RESPONSE_VALID); + } else + scic_sds_request_set_status( + sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS); break; - case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED: - - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_EPROTO); + /* only stp device gets suspended. */ + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_ACK_NAK_TO): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_PERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_NAK_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_DATA_LEN_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_ABORT_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_XR_WD_LEN): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_MAX_PLD_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_RESP): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_SDBFIS): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDB_ERR): + if (sci_req->protocol == SCIC_STP_PROTOCOL) { + scic_sds_request_set_status( + sci_req, + SCU_GET_COMPLETION_TL_STATUS(completion_code) >> + SCU_COMPLETION_TL_STATUS_SHIFT, + SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED); + } else { + scic_sds_request_set_status( + sci_req, + SCU_GET_COMPLETION_TL_STATUS(completion_code) >> + SCU_COMPLETION_TL_STATUS_SHIFT, + SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR); + } break; - case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED: - - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_CONN_RATE); + /* both stp/ssp device gets suspended */ + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LF_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_WRONG_DESTINATION): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_BAD_DESTINATION): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_ZONE_VIOLATION): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED): + scic_sds_request_set_status( + sci_req, + SCU_GET_COMPLETION_TL_STATUS(completion_code) >> + SCU_COMPLETION_TL_STATUS_SHIFT, + SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED); break; - case SCU_TASK_DONE_LL_R_ERR: - /* Also SCU_TASK_DONE_ACK_NAK_TO: */ - case SCU_TASK_DONE_LL_PERR: - case SCU_TASK_DONE_LL_SY_TERM: - /* Also SCU_TASK_DONE_NAK_ERR:*/ - case SCU_TASK_DONE_LL_LF_TERM: - /* Also SCU_TASK_DONE_DATA_LEN_ERR: */ - case SCU_TASK_DONE_LL_ABORT_ERR: - case SCU_TASK_DONE_SEQ_INV_TYPE: - /* Also SCU_TASK_DONE_UNEXP_XR: */ - case SCU_TASK_DONE_XR_IU_LEN_ERR: - case SCU_TASK_DONE_INV_FIS_LEN: - /* Also SCU_TASK_DONE_XR_WD_LEN: */ - case SCU_TASK_DONE_SDMA_ERR: - case SCU_TASK_DONE_OFFSET_ERR: - case SCU_TASK_DONE_MAX_PLD_ERR: - case SCU_TASK_DONE_LF_ERR: - case SCU_TASK_DONE_SMP_RESP_TO_ERR: /* Escalate to dev reset? */ - case SCU_TASK_DONE_SMP_LL_RX_ERR: - case SCU_TASK_DONE_UNEXP_DATA: - case SCU_TASK_DONE_UNEXP_SDBFIS: - case SCU_TASK_DONE_REG_ERR: - case SCU_TASK_DONE_SDB_ERR: - case SCU_TASK_DONE_TASK_ABORT: + /* neither ssp nor stp gets suspended. */ + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_NAK_CMD_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_XR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_XR_IU_LEN_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDMA_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_OFFSET_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_EXCESS_DATA): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_DATA): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_OPEN_FAIL): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_VIIT_ENTRY_NV): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_IIT_ENTRY_NV): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_RNCNV_OUTBOUND): default: - /* Task in the target is not done. */ - *response_ptr = SAS_TASK_UNDELIVERED; - *status_ptr = SAM_STAT_TASK_ABORTED; - request->complete_in_target = false; - - *complete_to_host_ptr = isci_perform_error_io_completion; + scic_sds_request_set_status( + sci_req, + SCU_GET_COMPLETION_TL_STATUS(completion_code) >> + SCU_COMPLETION_TL_STATUS_SHIFT, + SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR); break; } + + /* + * TODO: This is probably wrong for ACK/NAK timeout conditions + */ + + /* In all cases we will treat this as the completion of the IO req. */ + sci_base_state_machine_change_state( + &sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + return SCI_SUCCESS; } -/** - * isci_task_save_for_upper_layer_completion() - This function saves the - * request for later completion to the upper layer driver. - * @host: This parameter is a pointer to the host on which the the request - * should be queued (either as an error or success). - * @request: This parameter is the completed request. - * @response: This parameter is the response code for the completed task. - * @status: This parameter is the status code for the completed task. - * - * none. - */ -static void isci_task_save_for_upper_layer_completion( - struct isci_host *host, - struct isci_request *request, - enum service_response response, - enum exec_status status, - enum isci_completion_selection task_notification_selection) +enum sci_status +scic_sds_io_request_tc_completion(struct scic_sds_request *request, u32 completion_code) { - struct sas_task *task = isci_request_access_task(request); - - task_notification_selection - = isci_task_set_completion_status(task, response, status, - task_notification_selection); + if (request->state_machine.current_state_id == SCI_BASE_REQUEST_STATE_STARTED && + request->has_started_substate_machine == false) + return scic_sds_request_started_state_tc_completion_handler(request, completion_code); + else if (request->state_handlers->tc_completion_handler) + return request->state_handlers->tc_completion_handler(request, completion_code); + + dev_warn(scic_to_dev(request->owning_controller), + "%s: SCIC IO Request given task completion notification %x " + "while in wrong state %d\n", + __func__, + completion_code, + sci_base_state_machine_get_state(&request->state_machine)); - /* Tasks aborted specifically by a call to the lldd_abort_task - * function should not be completed to the host in the regular path. - */ - switch (task_notification_selection) { + return SCI_FAILURE_INVALID_STATE; - case isci_perform_normal_io_completion: +} - /* Normal notification (task_done) */ - dev_dbg(&host->pdev->dev, - "%s: Normal - task = %p, response=%d (%d), status=%d (%d)\n", +/* + * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T + * object receives a scic_sds_request_frame_handler() request. This method + * first determines the frame type received. If this is a response frame then + * the response data is copied to the io request response buffer for processing + * at completion time. If the frame type is not a response buffer an error is + * logged. enum sci_status SCI_SUCCESS SCI_FAILURE_INVALID_PARAMETER_VALUE + */ +static enum sci_status +scic_sds_request_started_state_frame_handler(struct scic_sds_request *sci_req, + u32 frame_index) +{ + enum sci_status status; + u32 *frame_header; + struct ssp_frame_hdr ssp_hdr; + ssize_t word_cnt; + + status = scic_sds_unsolicited_frame_control_get_header( + &(scic_sds_request_get_controller(sci_req)->uf_control), + frame_index, + (void **)&frame_header); + + word_cnt = sizeof(struct ssp_frame_hdr) / sizeof(u32); + sci_swab32_cpy(&ssp_hdr, frame_header, word_cnt); + + if (ssp_hdr.frame_type == SSP_RESPONSE) { + struct ssp_response_iu *resp_iu; + ssize_t word_cnt = SSP_RESP_IU_MAX_SIZE / sizeof(u32); + + status = scic_sds_unsolicited_frame_control_get_buffer( + &(scic_sds_request_get_controller(sci_req)->uf_control), + frame_index, + (void **)&resp_iu); + + sci_swab32_cpy(&sci_req->ssp.rsp, + resp_iu, word_cnt); + + resp_iu = &sci_req->ssp.rsp; + + if ((resp_iu->datapres == 0x01) || + (resp_iu->datapres == 0x02)) { + scic_sds_request_set_status( + sci_req, + SCU_TASK_DONE_CHECK_RESPONSE, + SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR); + } else + scic_sds_request_set_status( + sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS); + } else { + /* This was not a response frame why did it get forwarded? */ + dev_err(scic_to_dev(sci_req->owning_controller), + "%s: SCIC IO Request 0x%p received unexpected " + "frame %d type 0x%02x\n", __func__, - task, - task->task_status.resp, response, - task->task_status.stat, status); - /* Add to the completed list. */ - list_add(&request->completed_node, - &host->requests_to_complete); + sci_req, + frame_index, + ssp_hdr.frame_type); + } - /* Take the request off the device's pending request list. */ - list_del_init(&request->dev_node); - break; + /* + * In any case we are done with this frame buffer return it to the + * controller + */ + scic_sds_controller_release_frame( + sci_req->owning_controller, frame_index); - case isci_perform_aborted_io_completion: - /* No notification to libsas because this request is - * already in the abort path. - */ - dev_warn(&host->pdev->dev, - "%s: Aborted - task = %p, response=%d (%d), status=%d (%d)\n", - __func__, - task, - task->task_status.resp, response, - task->task_status.stat, status); + return SCI_SUCCESS; +} - /* Wake up whatever process was waiting for this - * request to complete. - */ - WARN_ON(request->io_request_completion == NULL); +/* + * ***************************************************************************** + * * COMPLETED STATE HANDLERS + * ***************************************************************************** */ - if (request->io_request_completion != NULL) { - /* Signal whoever is waiting that this - * request is complete. - */ - complete(request->io_request_completion); - } - break; +/* + * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T + * object receives a scic_sds_request_complete() request. This method frees up + * any io request resources that have been allocated and transitions the + * request to its final state. Consider stopping the state machine instead of + * transitioning to the final state? enum sci_status SCI_SUCCESS + */ +static enum sci_status scic_sds_request_completed_state_complete_handler( + struct scic_sds_request *request) +{ + if (request->was_tag_assigned_by_user != true) { + scic_controller_free_io_tag( + request->owning_controller, request->io_tag); + } - case isci_perform_error_io_completion: - /* Use sas_task_abort */ - dev_warn(&host->pdev->dev, - "%s: Error - task = %p, response=%d (%d), status=%d (%d)\n", - __func__, - task, - task->task_status.resp, response, - task->task_status.stat, status); - /* Add to the aborted list. */ - list_add(&request->completed_node, - &host->requests_to_errorback); - break; + if (request->saved_rx_frame_index != SCU_INVALID_FRAME_INDEX) { + scic_sds_controller_release_frame( + request->owning_controller, request->saved_rx_frame_index); + } - default: - dev_warn(&host->pdev->dev, - "%s: Unknown - task = %p, response=%d (%d), status=%d (%d)\n", - __func__, - task, - task->task_status.resp, response, - task->task_status.stat, status); + sci_base_state_machine_change_state(&request->state_machine, + SCI_BASE_REQUEST_STATE_FINAL); + return SCI_SUCCESS; +} - /* Add to the error to libsas list. */ - list_add(&request->completed_node, - &host->requests_to_errorback); +/* + * ***************************************************************************** + * * ABORTING STATE HANDLERS + * ***************************************************************************** */ + +/* + * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T + * object receives a scic_sds_request_terminate() request. This method is the + * io request aborting state abort handlers. On receipt of a multiple + * terminate requests the io request will transition to the completed state. + * This should not happen in normal operation. enum sci_status SCI_SUCCESS + */ +static enum sci_status scic_sds_request_aborting_state_abort_handler( + struct scic_sds_request *request) +{ + sci_base_state_machine_change_state(&request->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + return SCI_SUCCESS; +} + +/* + * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T + * object receives a scic_sds_request_task_completion() request. This method + * decodes the completion type waiting for the abort task complete + * notification. When the abort task complete is received the io request + * transitions to the completed state. enum sci_status SCI_SUCCESS + */ +static enum sci_status scic_sds_request_aborting_state_tc_completion_handler( + struct scic_sds_request *sci_req, + u32 completion_code) +{ + switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { + case (SCU_TASK_DONE_GOOD << SCU_COMPLETION_TL_STATUS_SHIFT): + case (SCU_TASK_DONE_TASK_ABORT << SCU_COMPLETION_TL_STATUS_SHIFT): + scic_sds_request_set_status( + sci_req, SCU_TASK_DONE_TASK_ABORT, SCI_FAILURE_IO_TERMINATED + ); + + sci_base_state_machine_change_state(&sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + break; + + default: + /* + * Unless we get some strange error wait for the task abort to complete + * TODO: Should there be a state change for this completion? */ break; } + + return SCI_SUCCESS; +} + +/* + * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T + * object receives a scic_sds_request_frame_handler() request. This method + * discards the unsolicited frame since we are waiting for the abort task + * completion. enum sci_status SCI_SUCCESS + */ +static enum sci_status scic_sds_request_aborting_state_frame_handler( + struct scic_sds_request *sci_req, + u32 frame_index) +{ + /* TODO: Is it even possible to get an unsolicited frame in the aborting state? */ + + scic_sds_controller_release_frame( + sci_req->owning_controller, frame_index); + + return SCI_SUCCESS; } +static const struct scic_sds_io_request_state_handler scic_sds_request_state_handler_table[] = { + [SCI_BASE_REQUEST_STATE_INITIAL] = { + }, + [SCI_BASE_REQUEST_STATE_CONSTRUCTED] = { + .start_handler = scic_sds_request_constructed_state_start_handler, + .abort_handler = scic_sds_request_constructed_state_abort_handler, + }, + [SCI_BASE_REQUEST_STATE_STARTED] = { + .abort_handler = scic_sds_request_started_state_abort_handler, + .tc_completion_handler = scic_sds_request_started_state_tc_completion_handler, + .frame_handler = scic_sds_request_started_state_frame_handler, + }, + [SCI_BASE_REQUEST_STATE_COMPLETED] = { + .complete_handler = scic_sds_request_completed_state_complete_handler, + }, + [SCI_BASE_REQUEST_STATE_ABORTING] = { + .abort_handler = scic_sds_request_aborting_state_abort_handler, + .tc_completion_handler = scic_sds_request_aborting_state_tc_completion_handler, + .frame_handler = scic_sds_request_aborting_state_frame_handler, + }, + [SCI_BASE_REQUEST_STATE_FINAL] = { + }, +}; + + /** - * isci_request_io_request_complete() - This function is called by the sci core - * when an io request completes. - * @isci_host: This parameter specifies the ISCI host object - * @request: This parameter is the completed isci_request object. - * @completion_status: This parameter specifies the completion status from the - * sci core. + * isci_request_process_response_iu() - This function sets the status and + * response iu, in the task struct, from the request object for the upper + * layer driver. + * @sas_task: This parameter is the task struct from the upper layer driver. + * @resp_iu: This parameter points to the response iu of the completed request. + * @dev: This parameter specifies the linux device struct. * * none. */ -void isci_request_io_request_complete( - struct isci_host *isci_host, - struct isci_request *request, - enum sci_io_status completion_status) +static void isci_request_process_response_iu( + struct sas_task *task, + struct ssp_response_iu *resp_iu, + struct device *dev) { - struct sas_task *task = isci_request_access_task(request); - struct ssp_response_iu *resp_iu; - void *resp_buf; - unsigned long task_flags; - struct isci_remote_device *isci_device = request->isci_device; - enum service_response response = SAS_TASK_UNDELIVERED; - enum exec_status status = SAS_ABORTED_TASK; - enum isci_request_status request_status; - enum isci_completion_selection complete_to_host - = isci_perform_normal_io_completion; - - dev_dbg(&isci_host->pdev->dev, - "%s: request = %p, task = %p,\n" - "task->data_dir = %d completion_status = 0x%x\n", + dev_dbg(dev, + "%s: resp_iu = %p " + "resp_iu->status = 0x%x,\nresp_iu->datapres = %d " + "resp_iu->response_data_len = %x, " + "resp_iu->sense_data_len = %x\nrepsonse data: ", __func__, - request, - task, - task->data_dir, - completion_status); + resp_iu, + resp_iu->status, + resp_iu->datapres, + resp_iu->response_data_len, + resp_iu->sense_data_len); - spin_lock(&request->state_lock); - request_status = isci_request_get_state(request); + task->task_status.stat = resp_iu->status; - /* Decode the request status. Note that if the request has been - * aborted by a task management function, we don't care - * what the status is. - */ - switch (request_status) { + /* libsas updates the task status fields based on the response iu. */ + sas_ssp_task_response(dev, task, resp_iu); +} - case aborted: - /* "aborted" indicates that the request was aborted by a task - * management function, since once a task management request is - * perfomed by the device, the request only completes because - * of the subsequent driver terminate. - * - * Aborted also means an external thread is explicitly managing - * this request, so that we do not complete it up the stack. - * - * The target is still there (since the TMF was successful). - */ - request->complete_in_target = true; - response = SAS_TASK_COMPLETE; +/** + * isci_request_set_open_reject_status() - This function prepares the I/O + * completion for OPEN_REJECT conditions. + * @request: This parameter is the completed isci_request object. + * @response_ptr: This parameter specifies the service response for the I/O. + * @status_ptr: This parameter specifies the exec status for the I/O. + * @complete_to_host_ptr: This parameter specifies the action to be taken by + * the LLDD with respect to completing this request or forcing an abort + * condition on the I/O. + * @open_rej_reason: This parameter specifies the encoded reason for the + * abandon-class reject. + * + * none. + */ +static void 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 isci_completion_selection *complete_to_host_ptr, + enum sas_open_rej_reason open_rej_reason) +{ + /* Task in the target is done. */ + request->complete_in_target = true; + *response_ptr = SAS_TASK_UNDELIVERED; + *status_ptr = SAS_OPEN_REJECT; + *complete_to_host_ptr = isci_perform_normal_io_completion; + task->task_status.open_rej_reason = open_rej_reason; +} - /* See if the device has been/is being stopped. Note - * that we ignore the quiesce state, since we are - * concerned about the actual device state. - */ - if ((isci_device->status == isci_stopping) - || (isci_device->status == isci_stopped) - ) - status = SAS_DEVICE_UNKNOWN; - else - status = SAS_ABORTED_TASK; +/** + * isci_request_handle_controller_specific_errors() - This function decodes + * controller-specific I/O completion error conditions. + * @request: This parameter is the completed isci_request object. + * @response_ptr: This parameter specifies the service response for the I/O. + * @status_ptr: This parameter specifies the exec status for the I/O. + * @complete_to_host_ptr: This parameter specifies the action to be taken by + * the LLDD with respect to completing this request or forcing an abort + * condition on the I/O. + * + * none. + */ +static void isci_request_handle_controller_specific_errors( + struct isci_remote_device *isci_device, + struct isci_request *request, + struct sas_task *task, + enum service_response *response_ptr, + enum exec_status *status_ptr, + enum isci_completion_selection *complete_to_host_ptr) +{ + unsigned int cstatus; - complete_to_host = isci_perform_aborted_io_completion; - /* This was an aborted request. */ + cstatus = request->sci.scu_status; - spin_unlock(&request->state_lock); - break; + dev_dbg(&request->isci_host->pdev->dev, + "%s: %p SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR " + "- controller status = 0x%x\n", + __func__, request, cstatus); - case aborting: - /* aborting means that the task management function tried and - * failed to abort the request. We need to note the request - * as SAS_TASK_UNDELIVERED, so that the scsi mid layer marks the - * target as down. - * - * Aborting also means an external thread is explicitly managing - * this request, so that we do not complete it up the stack. - */ - request->complete_in_target = true; - response = SAS_TASK_UNDELIVERED; + /* Decode the controller-specific errors; most + * important is to recognize those conditions in which + * the target may still have a task outstanding that + * must be aborted. + * + * Note that there are SCU completion codes being + * named in the decode below for which SCIC has already + * done work to handle them in a way other than as + * a controller-specific completion code; these are left + * in the decode below for completeness sake. + */ + switch (cstatus) { + case SCU_TASK_DONE_DMASETUP_DIRERR: + /* Also SCU_TASK_DONE_SMP_FRM_TYPE_ERR: */ + case SCU_TASK_DONE_XFERCNT_ERR: + /* Also SCU_TASK_DONE_SMP_UFI_ERR: */ + if (task->task_proto == SAS_PROTOCOL_SMP) { + /* SCU_TASK_DONE_SMP_UFI_ERR == Task Done. */ + *response_ptr = SAS_TASK_COMPLETE; - if ((isci_device->status == isci_stopping) || - (isci_device->status == isci_stopped)) - /* The device has been /is being stopped. Note that - * we ignore the quiesce state, since we are + /* See if the device has been/is being stopped. Note + * that we ignore the quiesce state, since we are * concerned about the actual device state. */ - status = SAS_DEVICE_UNKNOWN; - else - status = SAS_PHY_DOWN; + if ((isci_device->status == isci_stopping) || + (isci_device->status == isci_stopped)) + *status_ptr = SAS_DEVICE_UNKNOWN; + else + *status_ptr = SAS_ABORTED_TASK; - complete_to_host = isci_perform_aborted_io_completion; + request->complete_in_target = true; - /* This was an aborted request. */ + *complete_to_host_ptr = + isci_perform_normal_io_completion; + } else { + /* Task in the target is not done. */ + *response_ptr = SAS_TASK_UNDELIVERED; - spin_unlock(&request->state_lock); - break; + if ((isci_device->status == isci_stopping) || + (isci_device->status == isci_stopped)) + *status_ptr = SAS_DEVICE_UNKNOWN; + else + *status_ptr = SAM_STAT_TASK_ABORTED; - case terminating: + request->complete_in_target = false; - /* This was an terminated request. This happens when - * the I/O is being terminated because of an action on - * the device (reset, tear down, etc.), and the I/O needs - * to be completed up the stack. + *complete_to_host_ptr = + isci_perform_error_io_completion; + } + + break; + + case SCU_TASK_DONE_CRC_ERR: + case SCU_TASK_DONE_NAK_CMD_ERR: + case SCU_TASK_DONE_EXCESS_DATA: + case SCU_TASK_DONE_UNEXP_FIS: + /* Also SCU_TASK_DONE_UNEXP_RESP: */ + case SCU_TASK_DONE_VIIT_ENTRY_NV: /* TODO - conditions? */ + case SCU_TASK_DONE_IIT_ENTRY_NV: /* TODO - conditions? */ + case SCU_TASK_DONE_RNCNV_OUTBOUND: /* TODO - conditions? */ + /* These are conditions in which the target + * has completed the task, so that no cleanup + * is necessary. */ - request->complete_in_target = true; - response = SAS_TASK_UNDELIVERED; + *response_ptr = SAS_TASK_COMPLETE; /* See if the device has been/is being stopped. Note * that we ignore the quiesce state, since we are @@ -953,208 +1341,1206 @@ void isci_request_io_request_complete( */ if ((isci_device->status == isci_stopping) || (isci_device->status == isci_stopped)) - status = SAS_DEVICE_UNKNOWN; + *status_ptr = SAS_DEVICE_UNKNOWN; else - status = SAS_ABORTED_TASK; - - complete_to_host = isci_perform_aborted_io_completion; + *status_ptr = SAS_ABORTED_TASK; - /* This was a terminated request. */ + request->complete_in_target = true; - spin_unlock(&request->state_lock); + *complete_to_host_ptr = isci_perform_normal_io_completion; break; - default: - /* The request is done from an SCU HW perspective. */ - request->status = completed; + /* Note that the only open reject completion codes seen here will be + * abandon-class codes; all others are automatically retried in the SCU. + */ + case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION: - spin_unlock(&request->state_lock); + isci_request_set_open_reject_status( + request, task, response_ptr, status_ptr, + complete_to_host_ptr, SAS_OREJ_WRONG_DEST); + break; - /* This is an active request being completed from the core. */ - switch (completion_status) { + case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION: - case SCI_IO_FAILURE_RESPONSE_VALID: - dev_dbg(&isci_host->pdev->dev, - "%s: SCI_IO_FAILURE_RESPONSE_VALID (%p/%p)\n", - __func__, - request, - task); + /* Note - the return of AB0 will change when + * libsas implements detection of zone violations. + */ + isci_request_set_open_reject_status( + request, task, response_ptr, status_ptr, + complete_to_host_ptr, SAS_OREJ_RESV_AB0); + break; - if (sas_protocol_ata(task->task_proto)) { - resp_buf = &request->sci.stp.rsp; - isci_request_process_stp_response(task, - resp_buf); - } else if (SAS_PROTOCOL_SSP == task->task_proto) { + case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1: - /* crack the iu response buffer. */ - resp_iu = &request->sci.ssp.rsp; - isci_request_process_response_iu(task, resp_iu, - &isci_host->pdev->dev); + isci_request_set_open_reject_status( + request, task, response_ptr, status_ptr, + complete_to_host_ptr, SAS_OREJ_RESV_AB1); + break; - } else if (SAS_PROTOCOL_SMP == task->task_proto) { + case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2: - dev_err(&isci_host->pdev->dev, - "%s: SCI_IO_FAILURE_RESPONSE_VALID: " - "SAS_PROTOCOL_SMP protocol\n", - __func__); + isci_request_set_open_reject_status( + request, task, response_ptr, status_ptr, + complete_to_host_ptr, SAS_OREJ_RESV_AB2); + break; - } else - dev_err(&isci_host->pdev->dev, - "%s: unknown protocol\n", __func__); + case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3: - /* use the task status set in the task struct by the - * isci_request_process_response_iu call. - */ - request->complete_in_target = true; - response = task->task_status.resp; - status = task->task_status.stat; - break; + isci_request_set_open_reject_status( + request, task, response_ptr, status_ptr, + complete_to_host_ptr, SAS_OREJ_RESV_AB3); + break; - case SCI_IO_SUCCESS: - case SCI_IO_SUCCESS_IO_DONE_EARLY: + case SCU_TASK_OPEN_REJECT_BAD_DESTINATION: - response = SAS_TASK_COMPLETE; - status = SAM_STAT_GOOD; - request->complete_in_target = true; + isci_request_set_open_reject_status( + request, task, response_ptr, status_ptr, + complete_to_host_ptr, SAS_OREJ_BAD_DEST); + break; - if (task->task_proto == SAS_PROTOCOL_SMP) { - void *rsp = &request->sci.smp.rsp; + case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY: - dev_dbg(&isci_host->pdev->dev, - "%s: SMP protocol completion\n", - __func__); + isci_request_set_open_reject_status( + request, task, response_ptr, status_ptr, + complete_to_host_ptr, SAS_OREJ_STP_NORES); + break; - sg_copy_from_buffer( - &task->smp_task.smp_resp, 1, - rsp, sizeof(struct smp_resp)); - } else if (completion_status - == SCI_IO_SUCCESS_IO_DONE_EARLY) { + case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED: - /* This was an SSP / STP / SATA transfer. - * There is a possibility that less data than - * the maximum was transferred. - */ - u32 transferred_length - = scic_io_request_get_number_of_bytes_transferred(&request->sci); + isci_request_set_open_reject_status( + request, task, response_ptr, status_ptr, + complete_to_host_ptr, SAS_OREJ_EPROTO); + break; - task->task_status.residual - = task->total_xfer_len - transferred_length; + case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED: - /* If there were residual bytes, call this an - * underrun. - */ - if (task->task_status.residual != 0) - status = SAS_DATA_UNDERRUN; + isci_request_set_open_reject_status( + request, task, response_ptr, status_ptr, + complete_to_host_ptr, SAS_OREJ_CONN_RATE); + break; - dev_dbg(&isci_host->pdev->dev, - "%s: SCI_IO_SUCCESS_IO_DONE_EARLY %d\n", - __func__, - status); + case SCU_TASK_DONE_LL_R_ERR: + /* Also SCU_TASK_DONE_ACK_NAK_TO: */ + case SCU_TASK_DONE_LL_PERR: + case SCU_TASK_DONE_LL_SY_TERM: + /* Also SCU_TASK_DONE_NAK_ERR:*/ + case SCU_TASK_DONE_LL_LF_TERM: + /* Also SCU_TASK_DONE_DATA_LEN_ERR: */ + case SCU_TASK_DONE_LL_ABORT_ERR: + case SCU_TASK_DONE_SEQ_INV_TYPE: + /* Also SCU_TASK_DONE_UNEXP_XR: */ + case SCU_TASK_DONE_XR_IU_LEN_ERR: + case SCU_TASK_DONE_INV_FIS_LEN: + /* Also SCU_TASK_DONE_XR_WD_LEN: */ + case SCU_TASK_DONE_SDMA_ERR: + case SCU_TASK_DONE_OFFSET_ERR: + case SCU_TASK_DONE_MAX_PLD_ERR: + case SCU_TASK_DONE_LF_ERR: + case SCU_TASK_DONE_SMP_RESP_TO_ERR: /* Escalate to dev reset? */ + case SCU_TASK_DONE_SMP_LL_RX_ERR: + case SCU_TASK_DONE_UNEXP_DATA: + case SCU_TASK_DONE_UNEXP_SDBFIS: + case SCU_TASK_DONE_REG_ERR: + case SCU_TASK_DONE_SDB_ERR: + case SCU_TASK_DONE_TASK_ABORT: + default: + /* Task in the target is not done. */ + *response_ptr = SAS_TASK_UNDELIVERED; + *status_ptr = SAM_STAT_TASK_ABORTED; + request->complete_in_target = false; - } else - dev_dbg(&isci_host->pdev->dev, - "%s: SCI_IO_SUCCESS\n", - __func__); + *complete_to_host_ptr = isci_perform_error_io_completion; + break; + } +} - break; +/** + * isci_task_save_for_upper_layer_completion() - This function saves the + * request for later completion to the upper layer driver. + * @host: This parameter is a pointer to the host on which the the request + * should be queued (either as an error or success). + * @request: This parameter is the completed request. + * @response: This parameter is the response code for the completed task. + * @status: This parameter is the status code for the completed task. + * + * none. + */ +static void isci_task_save_for_upper_layer_completion( + struct isci_host *host, + struct isci_request *request, + enum service_response response, + enum exec_status status, + enum isci_completion_selection task_notification_selection) +{ + struct sas_task *task = isci_request_access_task(request); - case SCI_IO_FAILURE_TERMINATED: - dev_dbg(&isci_host->pdev->dev, - "%s: SCI_IO_FAILURE_TERMINATED (%p/%p)\n", - __func__, - request, - task); + task_notification_selection + = isci_task_set_completion_status(task, response, status, + task_notification_selection); - /* The request was terminated explicitly. No handling - * is needed in the SCSI error handler path. - */ - request->complete_in_target = true; - response = SAS_TASK_UNDELIVERED; + /* Tasks aborted specifically by a call to the lldd_abort_task + * function should not be completed to the host in the regular path. + */ + switch (task_notification_selection) { - /* See if the device has been/is being stopped. Note - * that we ignore the quiesce state, since we are - * concerned about the actual device state. - */ - if ((isci_device->status == isci_stopping) || - (isci_device->status == isci_stopped)) - status = SAS_DEVICE_UNKNOWN; - else - status = SAS_ABORTED_TASK; + case isci_perform_normal_io_completion: - complete_to_host = isci_perform_normal_io_completion; - break; + /* Normal notification (task_done) */ + dev_dbg(&host->pdev->dev, + "%s: Normal - task = %p, response=%d (%d), status=%d (%d)\n", + __func__, + task, + task->task_status.resp, response, + task->task_status.stat, status); + /* Add to the completed list. */ + list_add(&request->completed_node, + &host->requests_to_complete); - case SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR: + /* Take the request off the device's pending request list. */ + list_del_init(&request->dev_node); + break; - isci_request_handle_controller_specific_errors( - isci_device, request, task, &response, &status, - &complete_to_host); + case isci_perform_aborted_io_completion: + /* No notification to libsas because this request is + * already in the abort path. + */ + dev_warn(&host->pdev->dev, + "%s: Aborted - task = %p, response=%d (%d), status=%d (%d)\n", + __func__, + task, + task->task_status.resp, response, + task->task_status.stat, status); - break; + /* Wake up whatever process was waiting for this + * request to complete. + */ + WARN_ON(request->io_request_completion == NULL); - case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED: - /* This is a special case, in that the I/O completion - * is telling us that the device needs a reset. - * In order for the device reset condition to be - * noticed, the I/O has to be handled in the error - * handler. Set the reset flag and cause the - * SCSI error thread to be scheduled. - */ - spin_lock_irqsave(&task->task_state_lock, task_flags); - task->task_state_flags |= SAS_TASK_NEED_DEV_RESET; + if (request->io_request_completion != NULL) { + + /* Signal whoever is waiting that this + * request is complete. + */ + complete(request->io_request_completion); + } + break; + + case isci_perform_error_io_completion: + /* Use sas_task_abort */ + dev_warn(&host->pdev->dev, + "%s: Error - task = %p, response=%d (%d), status=%d (%d)\n", + __func__, + task, + task->task_status.resp, response, + task->task_status.stat, status); + /* Add to the aborted list. */ + list_add(&request->completed_node, + &host->requests_to_errorback); + break; + + default: + dev_warn(&host->pdev->dev, + "%s: Unknown - task = %p, response=%d (%d), status=%d (%d)\n", + __func__, + task, + task->task_status.resp, response, + task->task_status.stat, status); + + /* Add to the error to libsas list. */ + list_add(&request->completed_node, + &host->requests_to_errorback); + break; + } +} + +static void isci_request_io_request_complete(struct isci_host *isci_host, + struct isci_request *request, + enum sci_io_status completion_status) +{ + struct sas_task *task = isci_request_access_task(request); + struct ssp_response_iu *resp_iu; + void *resp_buf; + unsigned long task_flags; + struct isci_remote_device *isci_device = request->isci_device; + enum service_response response = SAS_TASK_UNDELIVERED; + enum exec_status status = SAS_ABORTED_TASK; + enum isci_request_status request_status; + enum isci_completion_selection complete_to_host + = isci_perform_normal_io_completion; + + dev_dbg(&isci_host->pdev->dev, + "%s: request = %p, task = %p,\n" + "task->data_dir = %d completion_status = 0x%x\n", + __func__, + request, + task, + task->data_dir, + completion_status); + + spin_lock(&request->state_lock); + request_status = isci_request_get_state(request); + + /* Decode the request status. Note that if the request has been + * aborted by a task management function, we don't care + * what the status is. + */ + switch (request_status) { + + case aborted: + /* "aborted" indicates that the request was aborted by a task + * management function, since once a task management request is + * perfomed by the device, the request only completes because + * of the subsequent driver terminate. + * + * Aborted also means an external thread is explicitly managing + * this request, so that we do not complete it up the stack. + * + * The target is still there (since the TMF was successful). + */ + request->complete_in_target = true; + response = SAS_TASK_COMPLETE; + + /* See if the device has been/is being stopped. Note + * that we ignore the quiesce state, since we are + * concerned about the actual device state. + */ + if ((isci_device->status == isci_stopping) + || (isci_device->status == isci_stopped) + ) + status = SAS_DEVICE_UNKNOWN; + else + status = SAS_ABORTED_TASK; + + complete_to_host = isci_perform_aborted_io_completion; + /* This was an aborted request. */ + + spin_unlock(&request->state_lock); + break; + + case aborting: + /* aborting means that the task management function tried and + * failed to abort the request. We need to note the request + * as SAS_TASK_UNDELIVERED, so that the scsi mid layer marks the + * target as down. + * + * Aborting also means an external thread is explicitly managing + * this request, so that we do not complete it up the stack. + */ + request->complete_in_target = true; + response = SAS_TASK_UNDELIVERED; + + if ((isci_device->status == isci_stopping) || + (isci_device->status == isci_stopped)) + /* The device has been /is being stopped. Note that + * we ignore the quiesce state, since we are + * concerned about the actual device state. + */ + status = SAS_DEVICE_UNKNOWN; + else + status = SAS_PHY_DOWN; + + complete_to_host = isci_perform_aborted_io_completion; + + /* This was an aborted request. */ + + spin_unlock(&request->state_lock); + break; + + case terminating: + + /* This was an terminated request. This happens when + * the I/O is being terminated because of an action on + * the device (reset, tear down, etc.), and the I/O needs + * to be completed up the stack. + */ + request->complete_in_target = true; + response = SAS_TASK_UNDELIVERED; + + /* See if the device has been/is being stopped. Note + * that we ignore the quiesce state, since we are + * concerned about the actual device state. + */ + if ((isci_device->status == isci_stopping) || + (isci_device->status == isci_stopped)) + status = SAS_DEVICE_UNKNOWN; + else + status = SAS_ABORTED_TASK; + + complete_to_host = isci_perform_aborted_io_completion; + + /* This was a terminated request. */ + + spin_unlock(&request->state_lock); + break; + + default: + + /* The request is done from an SCU HW perspective. */ + request->status = completed; + + spin_unlock(&request->state_lock); + + /* This is an active request being completed from the core. */ + switch (completion_status) { + + case SCI_IO_FAILURE_RESPONSE_VALID: + dev_dbg(&isci_host->pdev->dev, + "%s: SCI_IO_FAILURE_RESPONSE_VALID (%p/%p)\n", + __func__, + request, + task); + + if (sas_protocol_ata(task->task_proto)) { + resp_buf = &request->sci.stp.rsp; + isci_request_process_stp_response(task, + resp_buf); + } else if (SAS_PROTOCOL_SSP == task->task_proto) { + + /* crack the iu response buffer. */ + resp_iu = &request->sci.ssp.rsp; + isci_request_process_response_iu(task, resp_iu, + &isci_host->pdev->dev); + + } else if (SAS_PROTOCOL_SMP == task->task_proto) { + + dev_err(&isci_host->pdev->dev, + "%s: SCI_IO_FAILURE_RESPONSE_VALID: " + "SAS_PROTOCOL_SMP protocol\n", + __func__); + + } else + dev_err(&isci_host->pdev->dev, + "%s: unknown protocol\n", __func__); + + /* use the task status set in the task struct by the + * isci_request_process_response_iu call. + */ + request->complete_in_target = true; + response = task->task_status.resp; + status = task->task_status.stat; + break; + + case SCI_IO_SUCCESS: + case SCI_IO_SUCCESS_IO_DONE_EARLY: + + response = SAS_TASK_COMPLETE; + status = SAM_STAT_GOOD; + request->complete_in_target = true; + + if (task->task_proto == SAS_PROTOCOL_SMP) { + void *rsp = &request->sci.smp.rsp; + + dev_dbg(&isci_host->pdev->dev, + "%s: SMP protocol completion\n", + __func__); + + sg_copy_from_buffer( + &task->smp_task.smp_resp, 1, + rsp, sizeof(struct smp_resp)); + } else if (completion_status + == SCI_IO_SUCCESS_IO_DONE_EARLY) { + + /* This was an SSP / STP / SATA transfer. + * There is a possibility that less data than + * the maximum was transferred. + */ + u32 transferred_length = sci_req_tx_bytes(&request->sci); + + task->task_status.residual + = task->total_xfer_len - transferred_length; + + /* If there were residual bytes, call this an + * underrun. + */ + if (task->task_status.residual != 0) + status = SAS_DATA_UNDERRUN; + + dev_dbg(&isci_host->pdev->dev, + "%s: SCI_IO_SUCCESS_IO_DONE_EARLY %d\n", + __func__, + status); + + } else + dev_dbg(&isci_host->pdev->dev, + "%s: SCI_IO_SUCCESS\n", + __func__); + + break; + + case SCI_IO_FAILURE_TERMINATED: + dev_dbg(&isci_host->pdev->dev, + "%s: SCI_IO_FAILURE_TERMINATED (%p/%p)\n", + __func__, + request, + task); + + /* The request was terminated explicitly. No handling + * is needed in the SCSI error handler path. + */ + request->complete_in_target = true; + response = SAS_TASK_UNDELIVERED; + + /* See if the device has been/is being stopped. Note + * that we ignore the quiesce state, since we are + * concerned about the actual device state. + */ + if ((isci_device->status == isci_stopping) || + (isci_device->status == isci_stopped)) + status = SAS_DEVICE_UNKNOWN; + else + status = SAS_ABORTED_TASK; + + complete_to_host = isci_perform_normal_io_completion; + break; + + case SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR: + + isci_request_handle_controller_specific_errors( + isci_device, request, task, &response, &status, + &complete_to_host); + + break; + + case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED: + /* This is a special case, in that the I/O completion + * is telling us that the device needs a reset. + * In order for the device reset condition to be + * noticed, the I/O has to be handled in the error + * handler. Set the reset flag and cause the + * SCSI error thread to be scheduled. + */ + spin_lock_irqsave(&task->task_state_lock, task_flags); + task->task_state_flags |= SAS_TASK_NEED_DEV_RESET; spin_unlock_irqrestore(&task->task_state_lock, task_flags); - /* Fail the I/O. */ - response = SAS_TASK_UNDELIVERED; - status = SAM_STAT_TASK_ABORTED; + /* Fail the I/O. */ + response = SAS_TASK_UNDELIVERED; + status = SAM_STAT_TASK_ABORTED; + + complete_to_host = isci_perform_error_io_completion; + request->complete_in_target = false; + break; + + default: + /* Catch any otherwise unhandled error codes here. */ + dev_warn(&isci_host->pdev->dev, + "%s: invalid completion code: 0x%x - " + "isci_request = %p\n", + __func__, completion_status, request); + + response = SAS_TASK_UNDELIVERED; + + /* See if the device has been/is being stopped. Note + * that we ignore the quiesce state, since we are + * concerned about the actual device state. + */ + if ((isci_device->status == isci_stopping) || + (isci_device->status == isci_stopped)) + status = SAS_DEVICE_UNKNOWN; + else + status = SAS_ABORTED_TASK; + + complete_to_host = isci_perform_error_io_completion; + request->complete_in_target = false; + break; + } + break; + } + + isci_request_unmap_sgl(request, isci_host->pdev); + + /* Put the completed request on the correct list */ + isci_task_save_for_upper_layer_completion(isci_host, request, response, + status, complete_to_host + ); + + /* complete the io request to the core. */ + scic_controller_complete_io(&isci_host->sci, + &isci_device->sci, + &request->sci); + /* set terminated handle so it cannot be completed or + * terminated again, and to cause any calls into abort + * task to recognize the already completed case. + */ + request->terminated = true; + + isci_host_can_dequeue(isci_host, 1); +} + +/** + * scic_sds_request_initial_state_enter() - + * @object: This parameter specifies the base object for which the state + * transition is occurring. + * + * This method implements the actions taken when entering the + * SCI_BASE_REQUEST_STATE_INITIAL state. This state is entered when the initial + * base request is constructed. Entry into the initial state sets all handlers + * for the io request object to their default handlers. none + */ +static void scic_sds_request_initial_state_enter(void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_request_state_handler_table, + SCI_BASE_REQUEST_STATE_INITIAL + ); +} + +/** + * scic_sds_request_constructed_state_enter() - + * @object: The io request object that is to enter the constructed state. + * + * This method implements the actions taken when entering the + * SCI_BASE_REQUEST_STATE_CONSTRUCTED state. The method sets the state handlers + * for the the constructed state. none + */ +static void scic_sds_request_constructed_state_enter(void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_request_state_handler_table, + SCI_BASE_REQUEST_STATE_CONSTRUCTED + ); +} + +/** + * scic_sds_request_started_state_enter() - + * @object: This parameter specifies the base object for which the state + * transition is occurring. This is cast into a SCIC_SDS_IO_REQUEST object. + * + * This method implements the actions taken when entering the + * SCI_BASE_REQUEST_STATE_STARTED state. If the io request object type is a + * SCSI Task request we must enter the started substate machine. none + */ +static void scic_sds_request_started_state_enter(void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_request_state_handler_table, + SCI_BASE_REQUEST_STATE_STARTED + ); + + /* + * Most of the request state machines have a started substate machine so + * start its execution on the entry to the started state. */ + if (sci_req->has_started_substate_machine == true) + sci_base_state_machine_start(&sci_req->started_substate_machine); +} + +/** + * scic_sds_request_started_state_exit() - + * @object: This parameter specifies the base object for which the state + * transition is occurring. This object is cast into a SCIC_SDS_IO_REQUEST + * object. + * + * This method implements the actions taken when exiting the + * SCI_BASE_REQUEST_STATE_STARTED state. For task requests the action will be + * to stop the started substate machine. none + */ +static void scic_sds_request_started_state_exit(void *object) +{ + struct scic_sds_request *sci_req = object; + + if (sci_req->has_started_substate_machine == true) + sci_base_state_machine_stop(&sci_req->started_substate_machine); +} + +/** + * scic_sds_request_completed_state_enter() - + * @object: This parameter specifies the base object for which the state + * transition is occurring. This object is cast into a SCIC_SDS_IO_REQUEST + * object. + * + * This method implements the actions taken when entering the + * SCI_BASE_REQUEST_STATE_COMPLETED state. This state is entered when the + * SCIC_SDS_IO_REQUEST has completed. The method will decode the request + * completion status and convert it to an enum sci_status to return in the + * completion callback function. none + */ +static void scic_sds_request_completed_state_enter(void *object) +{ + struct scic_sds_request *sci_req = object; + struct scic_sds_controller *scic = + scic_sds_request_get_controller(sci_req); + struct isci_host *ihost = scic_to_ihost(scic); + struct isci_request *ireq = sci_req_to_ireq(sci_req); + + SET_STATE_HANDLER(sci_req, + scic_sds_request_state_handler_table, + SCI_BASE_REQUEST_STATE_COMPLETED); + + /* Tell the SCI_USER that the IO request is complete */ + if (sci_req->is_task_management_request == false) + isci_request_io_request_complete(ihost, ireq, + sci_req->sci_status); + else + isci_task_request_complete(ihost, ireq, sci_req->sci_status); +} + +/** + * scic_sds_request_aborting_state_enter() - + * @object: This parameter specifies the base object for which the state + * transition is occurring. This object is cast into a SCIC_SDS_IO_REQUEST + * object. + * + * This method implements the actions taken when entering the + * SCI_BASE_REQUEST_STATE_ABORTING state. none + */ +static void scic_sds_request_aborting_state_enter(void *object) +{ + struct scic_sds_request *sci_req = object; + + /* Setting the abort bit in the Task Context is required by the silicon. */ + sci_req->task_context_buffer->abort = 1; + + SET_STATE_HANDLER( + sci_req, + scic_sds_request_state_handler_table, + SCI_BASE_REQUEST_STATE_ABORTING + ); +} + +/** + * scic_sds_request_final_state_enter() - + * @object: This parameter specifies the base object for which the state + * transition is occurring. This is cast into a SCIC_SDS_IO_REQUEST object. + * + * This method implements the actions taken when entering the + * SCI_BASE_REQUEST_STATE_FINAL state. The only action required is to put the + * state handlers in place. none + */ +static void scic_sds_request_final_state_enter(void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_request_state_handler_table, + SCI_BASE_REQUEST_STATE_FINAL + ); +} + +static const struct sci_base_state scic_sds_request_state_table[] = { + [SCI_BASE_REQUEST_STATE_INITIAL] = { + .enter_state = scic_sds_request_initial_state_enter, + }, + [SCI_BASE_REQUEST_STATE_CONSTRUCTED] = { + .enter_state = scic_sds_request_constructed_state_enter, + }, + [SCI_BASE_REQUEST_STATE_STARTED] = { + .enter_state = scic_sds_request_started_state_enter, + .exit_state = scic_sds_request_started_state_exit + }, + [SCI_BASE_REQUEST_STATE_COMPLETED] = { + .enter_state = scic_sds_request_completed_state_enter, + }, + [SCI_BASE_REQUEST_STATE_ABORTING] = { + .enter_state = scic_sds_request_aborting_state_enter, + }, + [SCI_BASE_REQUEST_STATE_FINAL] = { + .enter_state = scic_sds_request_final_state_enter, + }, +}; + +static void scic_sds_general_request_construct(struct scic_sds_controller *scic, + struct scic_sds_remote_device *sci_dev, + u16 io_tag, struct scic_sds_request *sci_req) +{ + sci_base_state_machine_construct(&sci_req->state_machine, sci_req, + scic_sds_request_state_table, SCI_BASE_REQUEST_STATE_INITIAL); + sci_base_state_machine_start(&sci_req->state_machine); + + sci_req->io_tag = io_tag; + sci_req->owning_controller = scic; + sci_req->target_device = sci_dev; + sci_req->has_started_substate_machine = false; + sci_req->protocol = SCIC_NO_PROTOCOL; + sci_req->saved_rx_frame_index = SCU_INVALID_FRAME_INDEX; + sci_req->device_sequence = scic_sds_remote_device_get_sequence(sci_dev); + + sci_req->sci_status = SCI_SUCCESS; + sci_req->scu_status = 0; + sci_req->post_context = 0xFFFFFFFF; + + sci_req->is_task_management_request = false; + + if (io_tag == SCI_CONTROLLER_INVALID_IO_TAG) { + sci_req->was_tag_assigned_by_user = false; + sci_req->task_context_buffer = NULL; + } else { + sci_req->was_tag_assigned_by_user = true; + + sci_req->task_context_buffer = + scic_sds_controller_get_task_context_buffer(scic, io_tag); + } +} + +static enum sci_status +scic_io_request_construct(struct scic_sds_controller *scic, + struct scic_sds_remote_device *sci_dev, + u16 io_tag, struct scic_sds_request *sci_req) +{ + struct domain_device *dev = sci_dev_to_domain(sci_dev); + enum sci_status status = SCI_SUCCESS; + + /* Build the common part of the request */ + scic_sds_general_request_construct(scic, sci_dev, io_tag, sci_req); + + if (sci_dev->rnc.remote_node_index == + SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) + return SCI_FAILURE_INVALID_REMOTE_DEVICE; + + if (dev->dev_type == SAS_END_DEV) + scic_sds_ssp_io_request_assign_buffers(sci_req); + else if ((dev->dev_type == SATA_DEV) || + (dev->tproto & SAS_PROTOCOL_STP)) { + scic_sds_stp_request_assign_buffers(sci_req); + memset(&sci_req->stp.cmd, 0, sizeof(sci_req->stp.cmd)); + } else if (dev_is_expander(dev)) { + scic_sds_smp_request_assign_buffers(sci_req); + memset(&sci_req->smp.cmd, 0, sizeof(sci_req->smp.cmd)); + } else + status = SCI_FAILURE_UNSUPPORTED_PROTOCOL; + + if (status == SCI_SUCCESS) { + memset(sci_req->task_context_buffer, 0, + offsetof(struct scu_task_context, sgl_pair_ab)); + } + + return status; +} + +enum sci_status scic_task_request_construct(struct scic_sds_controller *scic, + struct scic_sds_remote_device *sci_dev, + u16 io_tag, struct scic_sds_request *sci_req) +{ + struct domain_device *dev = sci_dev_to_domain(sci_dev); + enum sci_status status = SCI_SUCCESS; + + /* Build the common part of the request */ + scic_sds_general_request_construct(scic, sci_dev, io_tag, sci_req); + + if (dev->dev_type == SAS_END_DEV) { + scic_sds_ssp_task_request_assign_buffers(sci_req); + + sci_req->has_started_substate_machine = true; + + /* Construct the started sub-state machine. */ + sci_base_state_machine_construct( + &sci_req->started_substate_machine, + sci_req, + scic_sds_io_request_started_task_mgmt_substate_table, + SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION + ); + } else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) + scic_sds_stp_request_assign_buffers(sci_req); + else + status = SCI_FAILURE_UNSUPPORTED_PROTOCOL; + + if (status == SCI_SUCCESS) { + sci_req->is_task_management_request = true; + memset(sci_req->task_context_buffer, 0, sizeof(struct scu_task_context)); + } + + return status; +} + +static enum sci_status isci_request_ssp_request_construct( + struct isci_request *request) +{ + enum sci_status status; + + dev_dbg(&request->isci_host->pdev->dev, + "%s: request = %p\n", + __func__, + request); + status = scic_io_request_construct_basic_ssp(&request->sci); + return status; +} + +static enum sci_status isci_request_stp_request_construct( + struct isci_request *request) +{ + struct sas_task *task = isci_request_access_task(request); + enum sci_status status; + struct host_to_dev_fis *register_fis; + + dev_dbg(&request->isci_host->pdev->dev, + "%s: request = %p\n", + __func__, + request); + + /* Get the host_to_dev_fis from the core and copy + * the fis from the task into it. + */ + register_fis = isci_sata_task_to_fis_copy(task); + + status = scic_io_request_construct_basic_sata(&request->sci); + + /* Set the ncq tag in the fis, from the queue + * command in the task. + */ + if (isci_sata_is_task_ncq(task)) { + + isci_sata_set_ncq_tag( + register_fis, + task + ); + } + + return status; +} + +/* + * isci_smp_request_build() - This function builds the smp request. + * @ireq: This parameter points to the isci_request allocated in the + * request construct function. + * + * SCI_SUCCESS on successfull completion, or specific failure code. + */ +static enum sci_status isci_smp_request_build(struct isci_request *ireq) +{ + enum sci_status status = SCI_FAILURE; + struct sas_task *task = isci_request_access_task(ireq); + struct scic_sds_request *sci_req = &ireq->sci; + + dev_dbg(&ireq->isci_host->pdev->dev, + "%s: request = %p\n", __func__, ireq); + + dev_dbg(&ireq->isci_host->pdev->dev, + "%s: smp_req len = %d\n", + __func__, + task->smp_task.smp_req.length); + + /* copy the smp_command to the address; */ + sg_copy_to_buffer(&task->smp_task.smp_req, 1, + &sci_req->smp.cmd, + sizeof(struct smp_req)); + + status = scic_io_request_construct_smp(sci_req); + if (status != SCI_SUCCESS) + dev_warn(&ireq->isci_host->pdev->dev, + "%s: failed with status = %d\n", + __func__, + status); + + return status; +} + +/** + * isci_io_request_build() - This function builds the io request object. + * @isci_host: This parameter specifies the ISCI host object + * @request: This parameter points to the isci_request object allocated in the + * request construct function. + * @sci_device: This parameter is the handle for the sci core's remote device + * object that is the destination for this request. + * + * SCI_SUCCESS on successfull completion, or specific failure code. + */ +static enum sci_status isci_io_request_build( + struct isci_host *isci_host, + struct isci_request *request, + struct isci_remote_device *isci_device) +{ + enum sci_status status = SCI_SUCCESS; + struct sas_task *task = isci_request_access_task(request); + struct scic_sds_remote_device *sci_device = &isci_device->sci; + + dev_dbg(&isci_host->pdev->dev, + "%s: isci_device = 0x%p; request = %p, " + "num_scatter = %d\n", + __func__, + isci_device, + request, + task->num_scatter); + + /* map the sgl addresses, if present. + * libata does the mapping for sata devices + * before we get the request. + */ + if (task->num_scatter && + !sas_protocol_ata(task->task_proto) && + !(SAS_PROTOCOL_SMP & task->task_proto)) { + + request->num_sg_entries = dma_map_sg( + &isci_host->pdev->dev, + task->scatter, + task->num_scatter, + task->data_dir + ); + + if (request->num_sg_entries == 0) + return SCI_FAILURE_INSUFFICIENT_RESOURCES; + } + + /* build the common request object. For now, + * we will let the core allocate the IO tag. + */ + status = scic_io_request_construct(&isci_host->sci, sci_device, + SCI_CONTROLLER_INVALID_IO_TAG, + &request->sci); + + if (status != SCI_SUCCESS) { + dev_warn(&isci_host->pdev->dev, + "%s: failed request construct\n", + __func__); + return SCI_FAILURE; + } + + switch (task->task_proto) { + case SAS_PROTOCOL_SMP: + status = isci_smp_request_build(request); + break; + case SAS_PROTOCOL_SSP: + status = isci_request_ssp_request_construct(request); + break; + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: + case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: + status = isci_request_stp_request_construct(request); + break; + default: + dev_warn(&isci_host->pdev->dev, + "%s: unknown protocol\n", __func__); + return SCI_FAILURE; + } + + return SCI_SUCCESS; +} + +/** + * isci_request_alloc_core() - This function gets the request object from the + * isci_host dma cache. + * @isci_host: This parameter specifies the ISCI host object + * @isci_request: This parameter will contain the pointer to the new + * isci_request object. + * @isci_device: This parameter is the pointer to the isci remote device object + * that is the destination for this request. + * @gfp_flags: This parameter specifies the os allocation flags. + * + * SCI_SUCCESS on successfull completion, or specific failure code. + */ +static int isci_request_alloc_core( + struct isci_host *isci_host, + struct isci_request **isci_request, + struct isci_remote_device *isci_device, + gfp_t gfp_flags) +{ + int ret = 0; + dma_addr_t handle; + struct isci_request *request; + - complete_to_host = isci_perform_error_io_completion; - request->complete_in_target = false; - break; + /* get pointer to dma memory. This actually points + * to both the isci_remote_device object and the + * sci object. The isci object is at the beginning + * of the memory allocated here. + */ + request = dma_pool_alloc(isci_host->dma_pool, gfp_flags, &handle); + if (!request) { + dev_warn(&isci_host->pdev->dev, + "%s: dma_pool_alloc returned NULL\n", __func__); + return -ENOMEM; + } - default: - /* Catch any otherwise unhandled error codes here. */ - dev_warn(&isci_host->pdev->dev, - "%s: invalid completion code: 0x%x - " - "isci_request = %p\n", - __func__, completion_status, request); + /* initialize the request object. */ + spin_lock_init(&request->state_lock); + request->request_daddr = handle; + request->isci_host = isci_host; + request->isci_device = isci_device; + request->io_request_completion = NULL; + request->terminated = false; - response = SAS_TASK_UNDELIVERED; + request->num_sg_entries = 0; - /* See if the device has been/is being stopped. Note - * that we ignore the quiesce state, since we are - * concerned about the actual device state. - */ - if ((isci_device->status == isci_stopping) || - (isci_device->status == isci_stopped)) - status = SAS_DEVICE_UNKNOWN; - else - status = SAS_ABORTED_TASK; + request->complete_in_target = false; - complete_to_host = isci_perform_error_io_completion; - request->complete_in_target = false; - break; - } - break; + INIT_LIST_HEAD(&request->completed_node); + INIT_LIST_HEAD(&request->dev_node); + + *isci_request = request; + isci_request_change_state(request, allocated); + + return ret; +} + +static int isci_request_alloc_io( + struct isci_host *isci_host, + struct sas_task *task, + struct isci_request **isci_request, + struct isci_remote_device *isci_device, + gfp_t gfp_flags) +{ + int retval = isci_request_alloc_core(isci_host, isci_request, + isci_device, gfp_flags); + + if (!retval) { + (*isci_request)->ttype_ptr.io_task_ptr = task; + (*isci_request)->ttype = io_task; + + task->lldd_task = *isci_request; } + return retval; +} - isci_request_unmap_sgl(request, isci_host->pdev); +/** + * isci_request_alloc_tmf() - This function gets the request object from the + * isci_host dma cache and initializes the relevant fields as a sas_task. + * @isci_host: This parameter specifies the ISCI host object + * @sas_task: This parameter is the task struct from the upper layer driver. + * @isci_request: This parameter will contain the pointer to the new + * isci_request object. + * @isci_device: This parameter is the pointer to the isci remote device object + * that is the destination for this request. + * @gfp_flags: This parameter specifies the os allocation flags. + * + * SCI_SUCCESS on successfull completion, or specific failure code. + */ +int isci_request_alloc_tmf( + struct isci_host *isci_host, + struct isci_tmf *isci_tmf, + struct isci_request **isci_request, + struct isci_remote_device *isci_device, + gfp_t gfp_flags) +{ + int retval = isci_request_alloc_core(isci_host, isci_request, + isci_device, gfp_flags); - /* Put the completed request on the correct list */ - isci_task_save_for_upper_layer_completion(isci_host, request, response, - status, complete_to_host - ); + if (!retval) { - /* complete the io request to the core. */ - scic_controller_complete_io(&isci_host->sci, - &isci_device->sci, - &request->sci); - /* set terminated handle so it cannot be completed or - * terminated again, and to cause any calls into abort - * task to recognize the already completed case. + (*isci_request)->ttype_ptr.tmf_task_ptr = isci_tmf; + (*isci_request)->ttype = tmf_task; + } + return retval; +} + +/** + * isci_request_execute() - This function allocates the isci_request object, + * all fills in some common fields. + * @isci_host: This parameter specifies the ISCI host object + * @sas_task: This parameter is the task struct from the upper layer driver. + * @isci_request: This parameter will contain the pointer to the new + * isci_request object. + * @gfp_flags: This parameter specifies the os allocation flags. + * + * SCI_SUCCESS on successfull completion, or specific failure code. + */ +int isci_request_execute( + struct isci_host *isci_host, + struct sas_task *task, + struct isci_request **isci_request, + gfp_t gfp_flags) +{ + int ret = 0; + struct scic_sds_remote_device *sci_device; + enum sci_status status = SCI_FAILURE_UNSUPPORTED_PROTOCOL; + struct isci_remote_device *isci_device; + struct isci_request *request; + unsigned long flags; + + isci_device = task->dev->lldd_dev; + sci_device = &isci_device->sci; + + /* do common allocation and init of request object. */ + ret = isci_request_alloc_io( + isci_host, + task, + &request, + isci_device, + gfp_flags + ); + + if (ret) + goto out; + + status = isci_io_request_build(isci_host, request, isci_device); + if (status != SCI_SUCCESS) { + dev_warn(&isci_host->pdev->dev, + "%s: request_construct failed - status = 0x%x\n", + __func__, + status); + goto out; + } + + spin_lock_irqsave(&isci_host->scic_lock, flags); + + /* send the request, let the core assign the IO TAG. */ + status = scic_controller_start_io(&isci_host->sci, sci_device, + &request->sci, + SCI_CONTROLLER_INVALID_IO_TAG); + if (status != SCI_SUCCESS && + status != SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) { + dev_warn(&isci_host->pdev->dev, + "%s: failed request start (0x%x)\n", + __func__, status); + spin_unlock_irqrestore(&isci_host->scic_lock, flags); + goto out; + } + + /* Either I/O started OK, or the core has signaled that + * the device needs a target reset. + * + * In either case, hold onto the I/O for later. + * + * Update it's status and add it to the list in the + * remote device object. */ - request->terminated = true; + isci_request_change_state(request, started); + list_add(&request->dev_node, &isci_device->reqs_in_process); - isci_host_can_dequeue(isci_host, 1); + if (status == SCI_SUCCESS) { + /* Save the tag for possible task mgmt later. */ + request->io_tag = request->sci.io_tag; + } else { + /* The request did not really start in the + * hardware, so clear the request handle + * here so no terminations will be done. + */ + request->terminated = true; + } + spin_unlock_irqrestore(&isci_host->scic_lock, flags); + + if (status == + SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) { + /* Signal libsas that we need the SCSI error + * handler thread to work on this I/O and that + * we want a device reset. + */ + spin_lock_irqsave(&task->task_state_lock, flags); + task->task_state_flags |= SAS_TASK_NEED_DEV_RESET; + spin_unlock_irqrestore(&task->task_state_lock, flags); + + /* Cause this task to be scheduled in the SCSI error + * handler thread. + */ + isci_execpath_callback(isci_host, task, + sas_task_abort); + + /* Change the status, since we are holding + * the I/O until it is managed by the SCSI + * error handler. + */ + status = SCI_SUCCESS; + } + + out: + if (status != SCI_SUCCESS) { + /* release dma memory on failure. */ + isci_request_free(isci_host, request); + request = NULL; + ret = SCI_FAILURE; + } + + *isci_request = request; + return ret; } + + + diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h index 06786ece9bb2..932ea767c8c2 100644 --- a/drivers/scsi/isci/request.h +++ b/drivers/scsi/isci/request.h @@ -58,7 +58,8 @@ #include "isci.h" #include "host.h" -#include "scic_sds_request.h" +#include "scu_task_context.h" +#include "stp_request.h" /** * struct isci_request_status - This enum defines the possible states of an I/O @@ -82,6 +83,151 @@ enum task_type { tmf_task = 1 }; +enum sci_request_protocol { + SCIC_NO_PROTOCOL, + SCIC_SMP_PROTOCOL, + SCIC_SSP_PROTOCOL, + SCIC_STP_PROTOCOL +}; /* XXX remove me, use sas_task.dev instead */; + +struct scic_sds_request { + /** + * This field contains the information for the base request state machine. + */ + struct sci_base_state_machine state_machine; + + /** + * This field simply points to the controller to which this IO request + * is associated. + */ + struct scic_sds_controller *owning_controller; + + /** + * This field simply points to the remote device to which this IO request + * is associated. + */ + struct scic_sds_remote_device *target_device; + + /** + * This field is utilized to determine if the SCI user is managing + * the IO tag for this request or if the core is managing it. + */ + bool was_tag_assigned_by_user; + + /** + * This field indicates the IO tag for this request. The IO tag is + * comprised of the task_index and a sequence count. The sequence count + * is utilized to help identify tasks from one life to another. + */ + u16 io_tag; + + /** + * This field specifies the protocol being utilized for this + * IO request. + */ + enum sci_request_protocol protocol; + + /** + * This field indicates the completion status taken from the SCUs + * completion code. It indicates the completion result for the SCU hardware. + */ + u32 scu_status; + + /** + * This field indicates the completion status returned to the SCI user. It + * indicates the users view of the io request completion. + */ + u32 sci_status; + + /** + * This field contains the value to be utilized when posting (e.g. Post_TC, + * Post_TC_Abort) this request to the silicon. + */ + u32 post_context; + + struct scu_task_context *task_context_buffer; + struct scu_task_context tc ____cacheline_aligned; + + /* could be larger with sg chaining */ + #define SCU_SGL_SIZE ((SCU_IO_REQUEST_SGE_COUNT + 1) / 2) + struct scu_sgl_element_pair sg_table[SCU_SGL_SIZE] __attribute__ ((aligned(32))); + + /** + * This field indicates if this request is a task management request or + * normal IO request. + */ + bool is_task_management_request; + + /** + * This field indicates that this request contains an initialized started + * substate machine. + */ + bool has_started_substate_machine; + + /** + * This field is a pointer to the stored rx frame data. It is used in STP + * internal requests and SMP response frames. If this field is non-NULL the + * saved frame must be released on IO request completion. + * + * @todo In the future do we want to keep a list of RX frame buffers? + */ + u32 saved_rx_frame_index; + + /** + * This field specifies the data necessary to manage the sub-state + * machine executed while in the SCI_BASE_REQUEST_STATE_STARTED state. + */ + struct sci_base_state_machine started_substate_machine; + + /** + * This field specifies the current state handlers in place for this + * IO Request object. This field is updated each time the request + * changes state. + */ + const struct scic_sds_io_request_state_handler *state_handlers; + + /** + * This field in the recorded device sequence for the io request. This is + * recorded during the build operation and is compared in the start + * operation. If the sequence is different then there was a change of + * devices from the build to start operations. + */ + u8 device_sequence; + + union { + struct { + union { + struct ssp_cmd_iu cmd; + struct ssp_task_iu tmf; + }; + union { + struct ssp_response_iu rsp; + u8 rsp_buf[SSP_RESP_IU_MAX_SIZE]; + }; + } ssp; + + struct { + struct smp_req cmd; + struct smp_resp rsp; + } smp; + + struct { + struct scic_sds_stp_request req; + struct host_to_dev_fis cmd; + struct dev_to_host_fis rsp; + } stp; + }; + +}; + +static inline struct scic_sds_request *to_sci_req(struct scic_sds_stp_request *stp_req) +{ + struct scic_sds_request *sci_req; + + sci_req = container_of(stp_req, typeof(*sci_req), stp.req); + return sci_req; +} + struct isci_request { enum isci_request_status status; enum task_type ttype; @@ -125,6 +271,273 @@ static inline struct isci_request *sci_req_to_ireq(struct scic_sds_request *sci_ return ireq; } +/** + * enum sci_base_request_states - This enumeration depicts all the states for + * the common request state machine. + * + * + */ +enum sci_base_request_states { + /** + * Simply the initial state for the base request state machine. + */ + SCI_BASE_REQUEST_STATE_INITIAL, + + /** + * This state indicates that the request has been constructed. This state + * is entered from the INITIAL state. + */ + SCI_BASE_REQUEST_STATE_CONSTRUCTED, + + /** + * This state indicates that the request has been started. This state is + * entered from the CONSTRUCTED state. + */ + SCI_BASE_REQUEST_STATE_STARTED, + + /** + * This state indicates that the request has completed. + * This state is entered from the STARTED state. This state is entered from + * the ABORTING state. + */ + SCI_BASE_REQUEST_STATE_COMPLETED, + + /** + * This state indicates that the request is in the process of being + * terminated/aborted. + * This state is entered from the CONSTRUCTED state. + * This state is entered from the STARTED state. + */ + SCI_BASE_REQUEST_STATE_ABORTING, + + /** + * Simply the final state for the base request state machine. + */ + SCI_BASE_REQUEST_STATE_FINAL, +}; + +typedef enum sci_status (*scic_sds_io_request_handler_t) + (struct scic_sds_request *request); +typedef enum sci_status (*scic_sds_io_request_frame_handler_t) + (struct scic_sds_request *req, u32 frame); +typedef enum sci_status (*scic_sds_io_request_event_handler_t) + (struct scic_sds_request *req, u32 event); +typedef enum sci_status (*scic_sds_io_request_task_completion_handler_t) + (struct scic_sds_request *req, u32 completion_code); + +/** + * struct scic_sds_io_request_state_handler - This is the SDS core definition + * of the state handlers. + * + * + */ +struct scic_sds_io_request_state_handler { + /** + * The start_handler specifies the method invoked when a user attempts to + * start a request. + */ + scic_sds_io_request_handler_t start_handler; + + /** + * The abort_handler specifies the method invoked when a user attempts to + * abort a request. + */ + scic_sds_io_request_handler_t abort_handler; + + /** + * The complete_handler specifies the method invoked when a user attempts to + * complete a request. + */ + scic_sds_io_request_handler_t complete_handler; + + scic_sds_io_request_task_completion_handler_t tc_completion_handler; + scic_sds_io_request_event_handler_t event_handler; + scic_sds_io_request_frame_handler_t frame_handler; + +}; + +extern const struct sci_base_state scic_sds_io_request_started_task_mgmt_substate_table[]; + +/** + * scic_sds_request_get_controller() - + * + * This macro will return the controller for this io request object + */ +#define scic_sds_request_get_controller(sci_req) \ + ((sci_req)->owning_controller) + +/** + * scic_sds_request_get_device() - + * + * This macro will return the device for this io request object + */ +#define scic_sds_request_get_device(sci_req) \ + ((sci_req)->target_device) + +/** + * scic_sds_request_get_port() - + * + * This macro will return the port for this io request object + */ +#define scic_sds_request_get_port(sci_req) \ + scic_sds_remote_device_get_port(scic_sds_request_get_device(sci_req)) + +/** + * scic_sds_request_get_post_context() - + * + * This macro returns the constructed post context result for the io request. + */ +#define scic_sds_request_get_post_context(sci_req) \ + ((sci_req)->post_context) + +/** + * scic_sds_request_get_task_context() - + * + * This is a helper macro to return the os handle for this request object. + */ +#define scic_sds_request_get_task_context(request) \ + ((request)->task_context_buffer) + +/** + * scic_sds_request_set_status() - + * + * This macro will set the scu hardware status and sci request completion + * status for an io request. + */ +#define scic_sds_request_set_status(request, scu_status_code, sci_status_code) \ + { \ + (request)->scu_status = (scu_status_code); \ + (request)->sci_status = (sci_status_code); \ + } + +#define scic_sds_request_complete(a_request) \ + ((a_request)->state_handlers->complete_handler(a_request)) + + +extern enum sci_status +scic_sds_io_request_tc_completion(struct scic_sds_request *request, u32 completion_code); + +/** + * SCU_SGL_ZERO() - + * + * This macro zeros the hardware SGL element data + */ +#define SCU_SGL_ZERO(scu_sge) \ + { \ + (scu_sge).length = 0; \ + (scu_sge).address_lower = 0; \ + (scu_sge).address_upper = 0; \ + (scu_sge).address_modifier = 0; \ + } + +/** + * SCU_SGL_COPY() - + * + * This macro copys the SGL Element data from the host os to the hardware SGL + * elment data + */ +#define SCU_SGL_COPY(scu_sge, os_sge) \ + { \ + (scu_sge).length = sg_dma_len(sg); \ + (scu_sge).address_upper = \ + upper_32_bits(sg_dma_address(sg)); \ + (scu_sge).address_lower = \ + lower_32_bits(sg_dma_address(sg)); \ + (scu_sge).address_modifier = 0; \ + } + +void scic_sds_request_build_sgl(struct scic_sds_request *sci_req); +void scic_sds_stp_request_assign_buffers(struct scic_sds_request *sci_req); +void scic_sds_smp_request_assign_buffers(struct scic_sds_request *sci_req); +enum sci_status scic_sds_request_start(struct scic_sds_request *sci_req); +enum sci_status scic_sds_io_request_terminate(struct scic_sds_request *sci_req); +void scic_sds_io_request_copy_response(struct scic_sds_request *sci_req); +enum sci_status scic_sds_io_request_event_handler(struct scic_sds_request *sci_req, + u32 event_code); +enum sci_status scic_sds_io_request_frame_handler(struct scic_sds_request *sci_req, + u32 frame_index); +enum sci_status scic_sds_task_request_terminate(struct scic_sds_request *sci_req); +enum sci_status scic_sds_request_started_state_abort_handler(struct scic_sds_request *sci_req); + +/** + * enum _scic_sds_io_request_started_task_mgmt_substates - This enumeration + * depicts all of the substates for a task management request to be + * performed in the STARTED super-state. + * + * + */ +enum scic_sds_raw_request_started_task_mgmt_substates { + /** + * The AWAIT_TC_COMPLETION sub-state indicates that the started raw + * task management request is waiting for the transmission of the + * initial frame (i.e. command, task, etc.). + */ + SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION, + + /** + * This sub-state indicates that the started task management request + * is waiting for the reception of an unsolicited frame + * (i.e. response IU). + */ + SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE, +}; + + +/** + * enum _scic_sds_smp_request_started_substates - This enumeration depicts all + * of the substates for a SMP request to be performed in the STARTED + * super-state. + * + * + */ +enum scic_sds_smp_request_started_substates { + /** + * This sub-state indicates that the started task management request + * is waiting for the reception of an unsolicited frame + * (i.e. response IU). + */ + SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE, + + /** + * The AWAIT_TC_COMPLETION sub-state indicates that the started SMP request is + * waiting for the transmission of the initial frame (i.e. command, task, etc.). + */ + SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION, +}; + + + +/* XXX open code in caller */ +static inline void *scic_request_get_virt_addr(struct scic_sds_request *sci_req, + dma_addr_t phys_addr) +{ + struct isci_request *ireq = sci_req_to_ireq(sci_req); + dma_addr_t offset; + + BUG_ON(phys_addr < ireq->request_daddr); + + offset = phys_addr - ireq->request_daddr; + + BUG_ON(offset >= sizeof(*ireq)); + + return (char *)ireq + offset; +} + +/* XXX open code in caller */ +static inline dma_addr_t scic_io_request_get_dma_addr(struct scic_sds_request *sci_req, + void *virt_addr) +{ + struct isci_request *ireq = sci_req_to_ireq(sci_req); + + char *requested_addr = (char *)virt_addr; + char *base_addr = (char *)ireq; + + BUG_ON(requested_addr < base_addr); + BUG_ON((requested_addr - base_addr) >= sizeof(*ireq)); + + return ireq->request_daddr + (requested_addr - base_addr); +} + /** * This function gets the status of the request object. * @request: This parameter points to the isci_request object @@ -337,12 +750,6 @@ static inline void isci_request_unmap_sgl( } } - -void isci_request_io_request_complete( - struct isci_host *isci_host, - struct isci_request *request, - enum sci_io_status completion_status); - /** * isci_request_io_request_get_next_sge() - This function is called by the sci * core to retrieve the next sge for a given request. @@ -385,13 +792,16 @@ static inline void *isci_request_io_request_get_next_sge( return ret; } - -void isci_terminate_pending_requests( - struct isci_host *isci_host, - struct isci_remote_device *isci_device, - enum isci_request_status new_request_state); - - - - +void isci_terminate_pending_requests(struct isci_host *isci_host, + struct isci_remote_device *isci_device, + enum isci_request_status new_request_state); +enum sci_status scic_task_request_construct(struct scic_sds_controller *scic, + struct scic_sds_remote_device *sci_dev, + u16 io_tag, + struct scic_sds_request *sci_req); +enum sci_status scic_task_request_construct_ssp(struct scic_sds_request *sci_req); +enum sci_status scic_task_request_construct_sata(struct scic_sds_request *sci_req); +enum sci_status scic_io_request_construct_smp(struct scic_sds_request *sci_req); +void scic_stp_io_request_set_ncq_tag(struct scic_sds_request *sci_req, u16 ncq_tag); +void scic_sds_smp_request_copy_response(struct scic_sds_request *sci_req); #endif /* !defined(_ISCI_REQUEST_H_) */ diff --git a/drivers/scsi/isci/sata.c b/drivers/scsi/isci/sata.c index 08dabf08f7d7..b9b9271d4736 100644 --- a/drivers/scsi/isci/sata.c +++ b/drivers/scsi/isci/sata.c @@ -56,8 +56,6 @@ #include #include "isci.h" #include "remote_device.h" -#include "scic_io_request.h" -#include "scic_task_request.h" #include "task.h" #include "request.h" #include "sata.h" diff --git a/drivers/scsi/isci/smp_request.c b/drivers/scsi/isci/smp_request.c new file mode 100644 index 000000000000..d4750a761c58 --- /dev/null +++ b/drivers/scsi/isci/smp_request.c @@ -0,0 +1,518 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "state_machine.h" +#include "remote_device.h" +#include "request.h" +#include "scu_completion_codes.h" +#include "scu_task_context.h" +#include "host.h" + +static void scu_smp_request_construct_task_context( + struct scic_sds_request *sci_req, + struct smp_req *smp_req); + +void scic_sds_smp_request_assign_buffers(struct scic_sds_request *sci_req) +{ + if (sci_req->was_tag_assigned_by_user == false) + sci_req->task_context_buffer = &sci_req->tc; +} + +/* + * This function will fill in the SCU Task Context for a SMP request. The + * following important settings are utilized: -# task_type == + * SCU_TASK_TYPE_SMP. This simply indicates that a normal request type + * (i.e. non-raw frame) is being utilized to perform task management. -# + * control_frame == 1. This ensures that the proper endianess is set so + * that the bytes are transmitted in the right order for a smp request frame. + * @sci_req: This parameter specifies the smp request object being + * constructed. + * + */ +static void +scu_smp_request_construct_task_context(struct scic_sds_request *sci_req, + struct smp_req *smp_req) +{ + dma_addr_t dma_addr; + struct scic_sds_controller *scic; + struct scic_sds_remote_device *sci_dev; + struct scic_sds_port *sci_port; + struct scu_task_context *task_context; + ssize_t word_cnt = sizeof(struct smp_req) / sizeof(u32); + + /* byte swap the smp request. */ + sci_swab32_cpy(&sci_req->smp.cmd, smp_req, + word_cnt); + + task_context = scic_sds_request_get_task_context(sci_req); + + scic = scic_sds_request_get_controller(sci_req); + sci_dev = scic_sds_request_get_device(sci_req); + sci_port = scic_sds_request_get_port(sci_req); + + /* + * Fill in the TC with the its required data + * 00h + */ + task_context->priority = 0; + task_context->initiator_request = 1; + task_context->connection_rate = sci_dev->connection_rate; + task_context->protocol_engine_index = + scic_sds_controller_get_protocol_engine_group(scic); + task_context->logical_port_index = scic_sds_port_get_index(sci_port); + task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SMP; + task_context->abort = 0; + task_context->valid = SCU_TASK_CONTEXT_VALID; + task_context->context_type = SCU_TASK_CONTEXT_TYPE; + + /* 04h */ + task_context->remote_node_index = sci_dev->rnc.remote_node_index; + task_context->command_code = 0; + task_context->task_type = SCU_TASK_TYPE_SMP_REQUEST; + + /* 08h */ + task_context->link_layer_control = 0; + task_context->do_not_dma_ssp_good_response = 1; + task_context->strict_ordering = 0; + task_context->control_frame = 1; + task_context->timeout_enable = 0; + task_context->block_guard_enable = 0; + + /* 0ch */ + task_context->address_modifier = 0; + + /* 10h */ + task_context->ssp_command_iu_length = smp_req->req_len; + + /* 14h */ + task_context->transfer_length_bytes = 0; + + /* + * 18h ~ 30h, protocol specific + * since commandIU has been build by framework at this point, we just + * copy the frist DWord from command IU to this location. */ + memcpy(&task_context->type.smp, &sci_req->smp.cmd, sizeof(u32)); + + /* + * 40h + * "For SMP you could program it to zero. We would prefer that way + * so that done code will be consistent." - Venki + */ + task_context->task_phase = 0; + + if (sci_req->was_tag_assigned_by_user) { + /* + * Build the task context now since we have already read + * the data + */ + sci_req->post_context = + (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | + (scic_sds_controller_get_protocol_engine_group(scic) << + SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | + (scic_sds_port_get_index(sci_port) << + SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) | + scic_sds_io_tag_get_index(sci_req->io_tag)); + } else { + /* + * Build the task context now since we have already read + * the data. + * I/O tag index is not assigned because we have to wait + * until we get a TCi. + */ + sci_req->post_context = + (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | + (scic_sds_controller_get_protocol_engine_group(scic) << + SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | + (scic_sds_port_get_index(sci_port) << + SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)); + } + + /* + * Copy the physical address for the command buffer to the SCU Task + * Context command buffer should not contain command header. + */ + dma_addr = scic_io_request_get_dma_addr(sci_req, + ((char *) &sci_req->smp.cmd) + + sizeof(u32)); + + task_context->command_iu_upper = upper_32_bits(dma_addr); + task_context->command_iu_lower = lower_32_bits(dma_addr); + + /* SMP response comes as UF, so no need to set response IU address. */ + task_context->response_iu_upper = 0; + task_context->response_iu_lower = 0; +} + +/* + * This function processes an unsolicited frame while the SMP request is waiting + * for a response frame. It will copy the response data, release the + * unsolicited frame, and transition the request to the + * SCI_BASE_REQUEST_STATE_COMPLETED state. + * @sci_req: This parameter specifies the request for which the + * unsolicited frame was received. + * @frame_index: This parameter indicates the unsolicited frame index that + * should contain the response. + * + * This function returns an indication of whether the response frame was handled + * successfully or not. SCI_SUCCESS Currently this value is always returned and + * indicates successful processing of the TC response. + */ +static enum sci_status +scic_sds_smp_request_await_response_frame_handler(struct scic_sds_request *sci_req, + u32 frame_index) +{ + enum sci_status status; + void *frame_header; + struct smp_resp *rsp_hdr = &sci_req->smp.rsp; + ssize_t word_cnt = SMP_RESP_HDR_SZ / sizeof(u32); + + status = scic_sds_unsolicited_frame_control_get_header( + &(scic_sds_request_get_controller(sci_req)->uf_control), + frame_index, + &frame_header); + + /* byte swap the header. */ + sci_swab32_cpy(rsp_hdr, frame_header, word_cnt); + + if (rsp_hdr->frame_type == SMP_RESPONSE) { + void *smp_resp; + + status = scic_sds_unsolicited_frame_control_get_buffer( + &(scic_sds_request_get_controller(sci_req)->uf_control), + frame_index, + &smp_resp); + + word_cnt = (sizeof(struct smp_req) - SMP_RESP_HDR_SZ) / + sizeof(u32); + + sci_swab32_cpy(((u8 *) rsp_hdr) + SMP_RESP_HDR_SZ, + smp_resp, word_cnt); + + scic_sds_request_set_status( + sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS); + + sci_base_state_machine_change_state( + &sci_req->started_substate_machine, + SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION); + } else { + /* This was not a response frame why did it get forwarded? */ + dev_err(scic_to_dev(sci_req->owning_controller), + "%s: SCIC SMP Request 0x%p received unexpected frame " + "%d type 0x%02x\n", + __func__, + sci_req, + frame_index, + rsp_hdr->frame_type); + + scic_sds_request_set_status( + sci_req, + SCU_TASK_DONE_SMP_FRM_TYPE_ERR, + SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR); + + sci_base_state_machine_change_state( + &sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + } + + scic_sds_controller_release_frame(sci_req->owning_controller, + frame_index); + + return SCI_SUCCESS; +} + + +/** + * This method processes an abnormal TC completion while the SMP request is + * waiting for a response frame. It decides what happened to the IO based + * on TC completion status. + * @sci_req: This parameter specifies the request for which the TC + * completion was received. + * @completion_code: This parameter indicates the completion status information + * for the TC. + * + * Indicate if the tc completion handler was successful. SCI_SUCCESS currently + * this method always returns success. + */ +static enum sci_status scic_sds_smp_request_await_response_tc_completion_handler( + struct scic_sds_request *sci_req, + u32 completion_code) +{ + switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): + /* + * In the AWAIT RESPONSE state, any TC completion is unexpected. + * but if the TC has success status, we complete the IO anyway. */ + scic_sds_request_set_status( + sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS + ); + + sci_base_state_machine_change_state( + &sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + break; + + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR): + /* + * These status has been seen in a specific LSI expander, which sometimes + * is not able to send smp response within 2 ms. This causes our hardware + * break the connection and set TC completion with one of these SMP_XXX_XX_ERR + * status. For these type of error, we ask scic user to retry the request. */ + scic_sds_request_set_status( + sci_req, SCU_TASK_DONE_SMP_RESP_TO_ERR, SCI_FAILURE_RETRY_REQUIRED + ); + + sci_base_state_machine_change_state( + &sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + break; + + default: + /* + * All other completion status cause the IO to be complete. If a NAK + * was received, then it is up to the user to retry the request. */ + scic_sds_request_set_status( + sci_req, + SCU_NORMALIZE_COMPLETION_STATUS(completion_code), + SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR + ); + + sci_base_state_machine_change_state( + &sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + break; + } + + return SCI_SUCCESS; +} + + +/** + * This method processes the completions transport layer (TL) status to + * determine if the SMP request was sent successfully. If the SMP request + * was sent successfully, then the state for the SMP request transits to + * waiting for a response frame. + * @sci_req: This parameter specifies the request for which the TC + * completion was received. + * @completion_code: This parameter indicates the completion status information + * for the TC. + * + * Indicate if the tc completion handler was successful. SCI_SUCCESS currently + * this method always returns success. + */ +static enum sci_status scic_sds_smp_request_await_tc_completion_tc_completion_handler( + struct scic_sds_request *sci_req, + u32 completion_code) +{ + switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): + scic_sds_request_set_status( + sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS + ); + + sci_base_state_machine_change_state( + &sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + break; + + default: + /* + * All other completion status cause the IO to be complete. If a NAK + * was received, then it is up to the user to retry the request. */ + scic_sds_request_set_status( + sci_req, + SCU_NORMALIZE_COMPLETION_STATUS(completion_code), + SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR + ); + + sci_base_state_machine_change_state( + &sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + break; + } + + return SCI_SUCCESS; +} + + +static const struct scic_sds_io_request_state_handler scic_sds_smp_request_started_substate_handler_table[] = { + [SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE] = { + .abort_handler = scic_sds_request_started_state_abort_handler, + .tc_completion_handler = scic_sds_smp_request_await_response_tc_completion_handler, + .frame_handler = scic_sds_smp_request_await_response_frame_handler, + }, + [SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION] = { + .abort_handler = scic_sds_request_started_state_abort_handler, + .tc_completion_handler = scic_sds_smp_request_await_tc_completion_tc_completion_handler, + } +}; + +/** + * This method performs the actions required when entering the + * SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_RESPONSE sub-state. This + * includes setting the IO request state handlers for this sub-state. + * @object: This parameter specifies the request object for which the sub-state + * change is occurring. + * + * none. + */ +static void scic_sds_smp_request_started_await_response_substate_enter( + void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_smp_request_started_substate_handler_table, + SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE + ); +} + +/** + * This method performs the actions required when entering the + * SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION sub-state. + * This includes setting the SMP request state handlers for this sub-state. + * @object: This parameter specifies the request object for which the sub-state + * change is occurring. + * + * none. + */ +static void scic_sds_smp_request_started_await_tc_completion_substate_enter( + void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_smp_request_started_substate_handler_table, + SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION + ); +} + +static const struct sci_base_state scic_sds_smp_request_started_substate_table[] = { + [SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE] = { + .enter_state = scic_sds_smp_request_started_await_response_substate_enter, + }, + [SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION] = { + .enter_state = scic_sds_smp_request_started_await_tc_completion_substate_enter, + }, +}; + +/** + * This method is called by the SCI user to build an SMP IO request. + * + * - The user must have previously called scic_io_request_construct() on the + * supplied IO request. Indicate if the controller successfully built the IO + * request. SCI_SUCCESS This value is returned if the IO request was + * successfully built. SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned + * if the remote_device does not support the SMP protocol. + * SCI_FAILURE_INVALID_ASSOCIATION This value is returned if the user did not + * properly set the association between the SCIC IO request and the user's IO + * request. + */ +enum sci_status scic_io_request_construct_smp(struct scic_sds_request *sci_req) +{ + struct smp_req *smp_req = kmalloc(sizeof(*smp_req), GFP_KERNEL); + + if (!smp_req) + return SCI_FAILURE_INSUFFICIENT_RESOURCES; + + sci_req->protocol = SCIC_SMP_PROTOCOL; + sci_req->has_started_substate_machine = true; + + /* Construct the started sub-state machine. */ + sci_base_state_machine_construct( + &sci_req->started_substate_machine, + sci_req, + scic_sds_smp_request_started_substate_table, + SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE + ); + + /* Construct the SMP SCU Task Context */ + memcpy(smp_req, &sci_req->smp.cmd, sizeof(*smp_req)); + + /* + * Look at the SMP requests' header fields; for certain SAS 1.x SMP + * functions under SAS 2.0, a zero request length really indicates + * a non-zero default length. */ + if (smp_req->req_len == 0) { + switch (smp_req->func) { + case SMP_DISCOVER: + case SMP_REPORT_PHY_ERR_LOG: + case SMP_REPORT_PHY_SATA: + case SMP_REPORT_ROUTE_INFO: + smp_req->req_len = 2; + break; + case SMP_CONF_ROUTE_INFO: + case SMP_PHY_CONTROL: + case SMP_PHY_TEST_FUNCTION: + smp_req->req_len = 9; + break; + /* Default - zero is a valid default for 2.0. */ + } + } + + scu_smp_request_construct_task_context(sci_req, smp_req); + + sci_base_state_machine_change_state(&sci_req->state_machine, + SCI_BASE_REQUEST_STATE_CONSTRUCTED); + + kfree(smp_req); + + return SCI_SUCCESS; +} diff --git a/drivers/scsi/isci/ssp_request.c b/drivers/scsi/isci/ssp_request.c new file mode 100644 index 000000000000..4b6317aeef7d --- /dev/null +++ b/drivers/scsi/isci/ssp_request.c @@ -0,0 +1,240 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "host.h" +#include "request.h" +#include "state_machine.h" +#include "scu_task_context.h" +#include "scu_completion_codes.h" + +/** + * This method processes the completions transport layer (TL) status to + * determine if the RAW task management frame was sent successfully. If the + * raw frame was sent successfully, then the state for the task request + * transitions to waiting for a response frame. + * @sci_req: This parameter specifies the request for which the TC + * completion was received. + * @completion_code: This parameter indicates the completion status information + * for the TC. + * + * Indicate if the tc completion handler was successful. SCI_SUCCESS currently + * this method always returns success. + */ +static enum sci_status scic_sds_ssp_task_request_await_tc_completion_tc_completion_handler( + struct scic_sds_request *sci_req, + u32 completion_code) +{ + switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): + scic_sds_request_set_status( + sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS + ); + + sci_base_state_machine_change_state( + &sci_req->started_substate_machine, + SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE + ); + break; + + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_ACK_NAK_TO): + /* + * Currently, the decision is to simply allow the task request to + * timeout if the task IU wasn't received successfully. + * There is a potential for receiving multiple task responses if we + * decide to send the task IU again. */ + dev_warn(scic_to_dev(sci_req->owning_controller), + "%s: TaskRequest:0x%p CompletionCode:%x - " + "ACK/NAK timeout\n", + __func__, + sci_req, + completion_code); + + sci_base_state_machine_change_state( + &sci_req->started_substate_machine, + SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE + ); + break; + + default: + /* + * All other completion status cause the IO to be complete. If a NAK + * was received, then it is up to the user to retry the request. */ + scic_sds_request_set_status( + sci_req, + SCU_NORMALIZE_COMPLETION_STATUS(completion_code), + SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR + ); + + sci_base_state_machine_change_state(&sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + break; + } + + return SCI_SUCCESS; +} + +/** + * This method is responsible for processing a terminate/abort request for this + * TC while the request is waiting for the task management response + * unsolicited frame. + * @sci_req: This parameter specifies the request for which the + * termination was requested. + * + * This method returns an indication as to whether the abort request was + * successfully handled. need to update to ensure the received UF doesn't cause + * damage to subsequent requests (i.e. put the extended tag in a holding + * pattern for this particular device). + */ +static enum sci_status scic_sds_ssp_task_request_await_tc_response_abort_handler( + struct scic_sds_request *request) +{ + sci_base_state_machine_change_state(&request->state_machine, + SCI_BASE_REQUEST_STATE_ABORTING); + sci_base_state_machine_change_state(&request->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + return SCI_SUCCESS; +} + +/** + * This method processes an unsolicited frame while the task mgmt request is + * waiting for a response frame. It will copy the response data, release + * the unsolicited frame, and transition the request to the + * SCI_BASE_REQUEST_STATE_COMPLETED state. + * @sci_req: This parameter specifies the request for which the + * unsolicited frame was received. + * @frame_index: This parameter indicates the unsolicited frame index that + * should contain the response. + * + * This method returns an indication of whether the TC response frame was + * handled successfully or not. SCI_SUCCESS Currently this value is always + * returned and indicates successful processing of the TC response. Should + * probably update to check frame type and make sure it is a response frame. + */ +static enum sci_status scic_sds_ssp_task_request_await_tc_response_frame_handler( + struct scic_sds_request *request, + u32 frame_index) +{ + scic_sds_io_request_copy_response(request); + + sci_base_state_machine_change_state(&request->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + scic_sds_controller_release_frame(request->owning_controller, + frame_index); + return SCI_SUCCESS; +} + +static const struct scic_sds_io_request_state_handler scic_sds_ssp_task_request_started_substate_handler_table[] = { + [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION] = { + .abort_handler = scic_sds_request_started_state_abort_handler, + .tc_completion_handler = scic_sds_ssp_task_request_await_tc_completion_tc_completion_handler, + }, + [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE] = { + .abort_handler = scic_sds_ssp_task_request_await_tc_response_abort_handler, + .frame_handler = scic_sds_ssp_task_request_await_tc_response_frame_handler, + } +}; + +/** + * This method performs the actions required when entering the + * SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION + * sub-state. This includes setting the IO request state handlers for this + * sub-state. + * @object: This parameter specifies the request object for which the sub-state + * change is occurring. + * + * none. + */ +static void scic_sds_io_request_started_task_mgmt_await_tc_completion_substate_enter( + void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_ssp_task_request_started_substate_handler_table, + SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION + ); +} + +/** + * This method performs the actions required when entering the + * SCIC_SDS_IO_REQUEST_STARTED_SUBSTATE_AWAIT_TC_RESPONSE sub-state. This + * includes setting the IO request state handlers for this sub-state. + * @object: This parameter specifies the request object for which the sub-state + * change is occurring. + * + * none. + */ +static void scic_sds_io_request_started_task_mgmt_await_task_response_substate_enter( + void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_ssp_task_request_started_substate_handler_table, + SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE + ); +} + +const struct sci_base_state scic_sds_io_request_started_task_mgmt_substate_table[] = { + [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION] = { + .enter_state = scic_sds_io_request_started_task_mgmt_await_tc_completion_substate_enter, + }, + [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE] = { + .enter_state = scic_sds_io_request_started_task_mgmt_await_task_response_substate_enter, + }, +}; + diff --git a/drivers/scsi/isci/stp_request.c b/drivers/scsi/isci/stp_request.c new file mode 100644 index 000000000000..298086afa5aa --- /dev/null +++ b/drivers/scsi/isci/stp_request.c @@ -0,0 +1,1590 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "sas.h" +#include "state_machine.h" +#include "remote_device.h" +#include "stp_request.h" +#include "unsolicited_frame_control.h" +#include "scu_completion_codes.h" +#include "scu_event_codes.h" +#include "scu_task_context.h" +#include "request.h" + +void scic_sds_stp_request_assign_buffers(struct scic_sds_request *sci_req) +{ + if (sci_req->was_tag_assigned_by_user == false) + sci_req->task_context_buffer = &sci_req->tc; +} + +/** + * This method is will fill in the SCU Task Context for any type of SATA + * request. This is called from the various SATA constructors. + * @sci_req: The general IO request object which is to be used in + * constructing the SCU task context. + * @task_context: The buffer pointer for the SCU task context which is being + * constructed. + * + * The general io request construction is complete. The buffer assignment for + * the command buffer is complete. none Revisit task context construction to + * determine what is common for SSP/SMP/STP task context structures. + */ +static void scu_sata_reqeust_construct_task_context( + struct scic_sds_request *sci_req, + struct scu_task_context *task_context) +{ + dma_addr_t dma_addr; + struct scic_sds_controller *controller; + struct scic_sds_remote_device *target_device; + struct scic_sds_port *target_port; + + controller = scic_sds_request_get_controller(sci_req); + target_device = scic_sds_request_get_device(sci_req); + target_port = scic_sds_request_get_port(sci_req); + + /* Fill in the TC with the its required data */ + task_context->abort = 0; + task_context->priority = SCU_TASK_PRIORITY_NORMAL; + task_context->initiator_request = 1; + task_context->connection_rate = target_device->connection_rate; + task_context->protocol_engine_index = + scic_sds_controller_get_protocol_engine_group(controller); + task_context->logical_port_index = + scic_sds_port_get_index(target_port); + task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_STP; + task_context->valid = SCU_TASK_CONTEXT_VALID; + task_context->context_type = SCU_TASK_CONTEXT_TYPE; + + task_context->remote_node_index = + scic_sds_remote_device_get_index(sci_req->target_device); + task_context->command_code = 0; + + task_context->link_layer_control = 0; + task_context->do_not_dma_ssp_good_response = 1; + task_context->strict_ordering = 0; + task_context->control_frame = 0; + task_context->timeout_enable = 0; + task_context->block_guard_enable = 0; + + task_context->address_modifier = 0; + task_context->task_phase = 0x01; + + task_context->ssp_command_iu_length = + (sizeof(struct host_to_dev_fis) - sizeof(u32)) / sizeof(u32); + + /* Set the first word of the H2D REG FIS */ + task_context->type.words[0] = *(u32 *)&sci_req->stp.cmd; + + if (sci_req->was_tag_assigned_by_user) { + /* + * Build the task context now since we have already read + * the data + */ + sci_req->post_context = + (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | + (scic_sds_controller_get_protocol_engine_group( + controller) << + SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | + (scic_sds_port_get_index(target_port) << + SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) | + scic_sds_io_tag_get_index(sci_req->io_tag)); + } else { + /* + * Build the task context now since we have already read + * the data. + * I/O tag index is not assigned because we have to wait + * until we get a TCi. + */ + sci_req->post_context = + (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | + (scic_sds_controller_get_protocol_engine_group( + controller) << + SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | + (scic_sds_port_get_index(target_port) << + SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)); + } + + /* + * Copy the physical address for the command buffer to the SCU Task + * Context. We must offset the command buffer by 4 bytes because the + * first 4 bytes are transfered in the body of the TC. + */ + dma_addr = scic_io_request_get_dma_addr(sci_req, + ((char *) &sci_req->stp.cmd) + + sizeof(u32)); + + task_context->command_iu_upper = upper_32_bits(dma_addr); + task_context->command_iu_lower = lower_32_bits(dma_addr); + + /* SATA Requests do not have a response buffer */ + task_context->response_iu_upper = 0; + task_context->response_iu_lower = 0; +} + +/** + * + * @sci_req: + * + * This method will perform any general sata request construction. What part of + * SATA IO request construction is general? none + */ +static void scic_sds_stp_non_ncq_request_construct( + struct scic_sds_request *sci_req) +{ + sci_req->has_started_substate_machine = true; +} + +/** + * + * @sci_req: This parameter specifies the request to be constructed as an + * optimized request. + * @optimized_task_type: This parameter specifies whether the request is to be + * an UDMA request or a NCQ request. - A value of 0 indicates UDMA. - A + * value of 1 indicates NCQ. + * + * This method will perform request construction common to all types of STP + * requests that are optimized by the silicon (i.e. UDMA, NCQ). This method + * returns an indication as to whether the construction was successful. + */ +static void scic_sds_stp_optimized_request_construct(struct scic_sds_request *sci_req, + u8 optimized_task_type, + u32 len, + enum dma_data_direction dir) +{ + struct scu_task_context *task_context = sci_req->task_context_buffer; + + /* Build the STP task context structure */ + scu_sata_reqeust_construct_task_context(sci_req, task_context); + + /* Copy over the SGL elements */ + scic_sds_request_build_sgl(sci_req); + + /* Copy over the number of bytes to be transfered */ + task_context->transfer_length_bytes = len; + + if (dir == DMA_TO_DEVICE) { + /* + * The difference between the DMA IN and DMA OUT request task type + * values are consistent with the difference between FPDMA READ + * and FPDMA WRITE values. Add the supplied task type parameter + * to this difference to set the task type properly for this + * DATA OUT (WRITE) case. */ + task_context->task_type = optimized_task_type + (SCU_TASK_TYPE_DMA_OUT + - SCU_TASK_TYPE_DMA_IN); + } else { + /* + * For the DATA IN (READ) case, simply save the supplied + * optimized task type. */ + task_context->task_type = optimized_task_type; + } +} + +/** + * + * @sci_req: This parameter specifies the request to be constructed. + * + * This method will construct the STP UDMA request and its associated TC data. + * This method returns an indication as to whether the construction was + * successful. SCI_SUCCESS Currently this method always returns this value. + */ +enum sci_status scic_sds_stp_ncq_request_construct(struct scic_sds_request *sci_req, + u32 len, + enum dma_data_direction dir) +{ + scic_sds_stp_optimized_request_construct(sci_req, + SCU_TASK_TYPE_FPDMAQ_READ, + len, dir); + return SCI_SUCCESS; +} + +/** + * scu_stp_raw_request_construct_task_context - + * @sci_req: This parameter specifies the STP request object for which to + * construct a RAW command frame task context. + * @task_context: This parameter specifies the SCU specific task context buffer + * to construct. + * + * This method performs the operations common to all SATA/STP requests + * utilizing the raw frame method. none + */ +static void scu_stp_raw_request_construct_task_context( + struct scic_sds_stp_request *stp_req, + struct scu_task_context *task_context) +{ + struct scic_sds_request *sci_req = to_sci_req(stp_req); + + scu_sata_reqeust_construct_task_context(sci_req, task_context); + + task_context->control_frame = 0; + task_context->priority = SCU_TASK_PRIORITY_NORMAL; + task_context->task_type = SCU_TASK_TYPE_SATA_RAW_FRAME; + task_context->type.stp.fis_type = FIS_REGH2D; + task_context->transfer_length_bytes = sizeof(struct host_to_dev_fis) - sizeof(u32); +} + +void scic_stp_io_request_set_ncq_tag( + struct scic_sds_request *req, + u16 ncq_tag) +{ + /** + * @note This could be made to return an error to the user if the user + * attempts to set the NCQ tag in the wrong state. + */ + req->task_context_buffer->type.stp.ncq_tag = ncq_tag; +} + +/** + * + * @sci_req: + * + * Get the next SGL element from the request. - Check on which SGL element pair + * we are working - if working on SLG pair element A - advance to element B - + * else - check to see if there are more SGL element pairs for this IO request + * - if there are more SGL element pairs - advance to the next pair and return + * element A struct scu_sgl_element* + */ +static struct scu_sgl_element *scic_sds_stp_request_pio_get_next_sgl(struct scic_sds_stp_request *stp_req) +{ + struct scu_sgl_element *current_sgl; + struct scic_sds_request *sci_req = to_sci_req(stp_req); + struct scic_sds_request_pio_sgl *pio_sgl = &stp_req->type.pio.request_current; + + if (pio_sgl->sgl_set == SCU_SGL_ELEMENT_PAIR_A) { + if (pio_sgl->sgl_pair->B.address_lower == 0 && + pio_sgl->sgl_pair->B.address_upper == 0) { + current_sgl = NULL; + } else { + pio_sgl->sgl_set = SCU_SGL_ELEMENT_PAIR_B; + current_sgl = &pio_sgl->sgl_pair->B; + } + } else { + if (pio_sgl->sgl_pair->next_pair_lower == 0 && + pio_sgl->sgl_pair->next_pair_upper == 0) { + current_sgl = NULL; + } else { + u64 phys_addr; + + phys_addr = pio_sgl->sgl_pair->next_pair_upper; + phys_addr <<= 32; + phys_addr |= pio_sgl->sgl_pair->next_pair_lower; + + pio_sgl->sgl_pair = scic_request_get_virt_addr(sci_req, phys_addr); + pio_sgl->sgl_set = SCU_SGL_ELEMENT_PAIR_A; + current_sgl = &pio_sgl->sgl_pair->A; + } + } + + return current_sgl; +} + +/** + * + * @sci_req: + * @completion_code: + * + * This method processes a TC completion. The expected TC completion is for + * the transmission of the H2D register FIS containing the SATA/STP non-data + * request. This method always successfully processes the TC completion. + * SCI_SUCCESS This value is always returned. + */ +static enum sci_status scic_sds_stp_request_non_data_await_h2d_tc_completion_handler( + struct scic_sds_request *sci_req, + u32 completion_code) +{ + switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): + scic_sds_request_set_status( + sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS + ); + + sci_base_state_machine_change_state( + &sci_req->started_substate_machine, + SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE + ); + break; + + default: + /* + * All other completion status cause the IO to be complete. If a NAK + * was received, then it is up to the user to retry the request. */ + scic_sds_request_set_status( + sci_req, + SCU_NORMALIZE_COMPLETION_STATUS(completion_code), + SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR + ); + + sci_base_state_machine_change_state( + &sci_req->state_machine, SCI_BASE_REQUEST_STATE_COMPLETED); + break; + } + + return SCI_SUCCESS; +} + +/** + * + * @request: This parameter specifies the request for which a frame has been + * received. + * @frame_index: This parameter specifies the index of the frame that has been + * received. + * + * This method processes frames received from the target while waiting for a + * device to host register FIS. If a non-register FIS is received during this + * time, it is treated as a protocol violation from an IO perspective. Indicate + * if the received frame was processed successfully. + */ +static enum sci_status scic_sds_stp_request_non_data_await_d2h_frame_handler( + struct scic_sds_request *sci_req, + u32 frame_index) +{ + enum sci_status status; + struct dev_to_host_fis *frame_header; + u32 *frame_buffer; + struct scic_sds_stp_request *stp_req = &sci_req->stp.req; + struct scic_sds_controller *scic = sci_req->owning_controller; + + status = scic_sds_unsolicited_frame_control_get_header(&scic->uf_control, + frame_index, + (void **)&frame_header); + + if (status != SCI_SUCCESS) { + dev_err(scic_to_dev(sci_req->owning_controller), + "%s: SCIC IO Request 0x%p could not get frame header " + "for frame index %d, status %x\n", + __func__, stp_req, frame_index, status); + + return status; + } + + switch (frame_header->fis_type) { + case FIS_REGD2H: + scic_sds_unsolicited_frame_control_get_buffer(&scic->uf_control, + frame_index, + (void **)&frame_buffer); + + scic_sds_controller_copy_sata_response(&sci_req->stp.rsp, + frame_header, + frame_buffer); + + /* The command has completed with error */ + scic_sds_request_set_status(sci_req, SCU_TASK_DONE_CHECK_RESPONSE, + SCI_FAILURE_IO_RESPONSE_VALID); + break; + + default: + dev_warn(scic_to_dev(scic), + "%s: IO Request:0x%p Frame Id:%d protocol " + "violation occurred\n", __func__, stp_req, + frame_index); + + scic_sds_request_set_status(sci_req, SCU_TASK_DONE_UNEXP_FIS, + SCI_FAILURE_PROTOCOL_VIOLATION); + break; + } + + sci_base_state_machine_change_state(&sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + + /* Frame has been decoded return it to the controller */ + scic_sds_controller_release_frame(scic, frame_index); + + return status; +} + +/* --------------------------------------------------------------------------- */ + +static const struct scic_sds_io_request_state_handler scic_sds_stp_request_started_non_data_substate_handler_table[] = { + [SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE] = { + .abort_handler = scic_sds_request_started_state_abort_handler, + .tc_completion_handler = scic_sds_stp_request_non_data_await_h2d_tc_completion_handler, + }, + [SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE] = { + .abort_handler = scic_sds_request_started_state_abort_handler, + .frame_handler = scic_sds_stp_request_non_data_await_d2h_frame_handler, + } +}; + +static void scic_sds_stp_request_started_non_data_await_h2d_completion_enter( + void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_stp_request_started_non_data_substate_handler_table, + SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE + ); + + scic_sds_remote_device_set_working_request( + sci_req->target_device, sci_req + ); +} + +static void scic_sds_stp_request_started_non_data_await_d2h_enter(void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_stp_request_started_non_data_substate_handler_table, + SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE + ); +} + +/* --------------------------------------------------------------------------- */ + +static const struct sci_base_state scic_sds_stp_request_started_non_data_substate_table[] = { + [SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE] = { + .enter_state = scic_sds_stp_request_started_non_data_await_h2d_completion_enter, + }, + [SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE] = { + .enter_state = scic_sds_stp_request_started_non_data_await_d2h_enter, + }, +}; + +enum sci_status scic_sds_stp_non_data_request_construct(struct scic_sds_request *sci_req) +{ + struct scic_sds_stp_request *stp_req = &sci_req->stp.req; + + scic_sds_stp_non_ncq_request_construct(sci_req); + + /* Build the STP task context structure */ + scu_stp_raw_request_construct_task_context(stp_req, sci_req->task_context_buffer); + + sci_base_state_machine_construct(&sci_req->started_substate_machine, + sci_req, + scic_sds_stp_request_started_non_data_substate_table, + SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE); + + return SCI_SUCCESS; +} + +#define SCU_MAX_FRAME_BUFFER_SIZE 0x400 /* 1K is the maximum SCU frame data payload */ + +/* transmit DATA_FIS from (current sgl + offset) for input + * parameter length. current sgl and offset is alreay stored in the IO request + */ +static enum sci_status scic_sds_stp_request_pio_data_out_trasmit_data_frame( + struct scic_sds_request *sci_req, + u32 length) +{ + struct scic_sds_controller *scic = sci_req->owning_controller; + struct scic_sds_stp_request *stp_req = &sci_req->stp.req; + struct scu_task_context *task_context; + struct scu_sgl_element *current_sgl; + + /* Recycle the TC and reconstruct it for sending out DATA FIS containing + * for the data from current_sgl+offset for the input length + */ + task_context = scic_sds_controller_get_task_context_buffer(scic, + sci_req->io_tag); + + if (stp_req->type.pio.request_current.sgl_set == SCU_SGL_ELEMENT_PAIR_A) + current_sgl = &stp_req->type.pio.request_current.sgl_pair->A; + else + current_sgl = &stp_req->type.pio.request_current.sgl_pair->B; + + /* update the TC */ + task_context->command_iu_upper = current_sgl->address_upper; + task_context->command_iu_lower = current_sgl->address_lower; + task_context->transfer_length_bytes = length; + task_context->type.stp.fis_type = FIS_DATA; + + /* send the new TC out. */ + return scic_controller_continue_io(sci_req); +} + +static enum sci_status scic_sds_stp_request_pio_data_out_transmit_data(struct scic_sds_request *sci_req) +{ + + struct scu_sgl_element *current_sgl; + u32 sgl_offset; + u32 remaining_bytes_in_current_sgl = 0; + enum sci_status status = SCI_SUCCESS; + struct scic_sds_stp_request *stp_req = &sci_req->stp.req; + + sgl_offset = stp_req->type.pio.request_current.sgl_offset; + + if (stp_req->type.pio.request_current.sgl_set == SCU_SGL_ELEMENT_PAIR_A) { + current_sgl = &(stp_req->type.pio.request_current.sgl_pair->A); + remaining_bytes_in_current_sgl = stp_req->type.pio.request_current.sgl_pair->A.length - sgl_offset; + } else { + current_sgl = &(stp_req->type.pio.request_current.sgl_pair->B); + remaining_bytes_in_current_sgl = stp_req->type.pio.request_current.sgl_pair->B.length - sgl_offset; + } + + + if (stp_req->type.pio.pio_transfer_bytes > 0) { + if (stp_req->type.pio.pio_transfer_bytes >= remaining_bytes_in_current_sgl) { + /* recycle the TC and send the H2D Data FIS from (current sgl + sgl_offset) and length = remaining_bytes_in_current_sgl */ + status = scic_sds_stp_request_pio_data_out_trasmit_data_frame(sci_req, remaining_bytes_in_current_sgl); + if (status == SCI_SUCCESS) { + stp_req->type.pio.pio_transfer_bytes -= remaining_bytes_in_current_sgl; + + /* update the current sgl, sgl_offset and save for future */ + current_sgl = scic_sds_stp_request_pio_get_next_sgl(stp_req); + sgl_offset = 0; + } + } else if (stp_req->type.pio.pio_transfer_bytes < remaining_bytes_in_current_sgl) { + /* recycle the TC and send the H2D Data FIS from (current sgl + sgl_offset) and length = type.pio.pio_transfer_bytes */ + scic_sds_stp_request_pio_data_out_trasmit_data_frame(sci_req, stp_req->type.pio.pio_transfer_bytes); + + if (status == SCI_SUCCESS) { + /* Sgl offset will be adjusted and saved for future */ + sgl_offset += stp_req->type.pio.pio_transfer_bytes; + current_sgl->address_lower += stp_req->type.pio.pio_transfer_bytes; + stp_req->type.pio.pio_transfer_bytes = 0; + } + } + } + + if (status == SCI_SUCCESS) { + stp_req->type.pio.request_current.sgl_offset = sgl_offset; + } + + return status; +} + +/** + * + * @stp_request: The request that is used for the SGL processing. + * @data_buffer: The buffer of data to be copied. + * @length: The length of the data transfer. + * + * Copy the data from the buffer for the length specified to the IO reqeust SGL + * specified data region. enum sci_status + */ +static enum sci_status +scic_sds_stp_request_pio_data_in_copy_data_buffer(struct scic_sds_stp_request *stp_req, + u8 *data_buf, u32 len) +{ + struct scic_sds_request *sci_req; + struct isci_request *ireq; + u8 *src_addr; + int copy_len; + struct sas_task *task; + struct scatterlist *sg; + void *kaddr; + int total_len = len; + + sci_req = to_sci_req(stp_req); + ireq = sci_req_to_ireq(sci_req); + task = isci_request_access_task(ireq); + src_addr = data_buf; + + if (task->num_scatter > 0) { + sg = task->scatter; + + while (total_len > 0) { + struct page *page = sg_page(sg); + + copy_len = min_t(int, total_len, sg_dma_len(sg)); + kaddr = kmap_atomic(page, KM_IRQ0); + memcpy(kaddr + sg->offset, src_addr, copy_len); + kunmap_atomic(kaddr, KM_IRQ0); + total_len -= copy_len; + src_addr += copy_len; + sg = sg_next(sg); + } + } else { + BUG_ON(task->total_xfer_len < total_len); + memcpy(task->scatter, src_addr, total_len); + } + + return SCI_SUCCESS; +} + +/** + * + * @sci_req: The PIO DATA IN request that is to receive the data. + * @data_buffer: The buffer to copy from. + * + * Copy the data buffer to the io request data region. enum sci_status + */ +static enum sci_status scic_sds_stp_request_pio_data_in_copy_data( + struct scic_sds_stp_request *sci_req, + u8 *data_buffer) +{ + enum sci_status status; + + /* + * If there is less than 1K remaining in the transfer request + * copy just the data for the transfer */ + if (sci_req->type.pio.pio_transfer_bytes < SCU_MAX_FRAME_BUFFER_SIZE) { + status = scic_sds_stp_request_pio_data_in_copy_data_buffer( + sci_req, data_buffer, sci_req->type.pio.pio_transfer_bytes); + + if (status == SCI_SUCCESS) + sci_req->type.pio.pio_transfer_bytes = 0; + } else { + /* We are transfering the whole frame so copy */ + status = scic_sds_stp_request_pio_data_in_copy_data_buffer( + sci_req, data_buffer, SCU_MAX_FRAME_BUFFER_SIZE); + + if (status == SCI_SUCCESS) + sci_req->type.pio.pio_transfer_bytes -= SCU_MAX_FRAME_BUFFER_SIZE; + } + + return status; +} + +/** + * + * @sci_req: + * @completion_code: + * + * enum sci_status + */ +static enum sci_status scic_sds_stp_request_pio_await_h2d_completion_tc_completion_handler( + struct scic_sds_request *sci_req, + u32 completion_code) +{ + enum sci_status status = SCI_SUCCESS; + + switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): + scic_sds_request_set_status( + sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS + ); + + sci_base_state_machine_change_state( + &sci_req->started_substate_machine, + SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE + ); + break; + + default: + /* + * All other completion status cause the IO to be complete. If a NAK + * was received, then it is up to the user to retry the request. */ + scic_sds_request_set_status( + sci_req, + SCU_NORMALIZE_COMPLETION_STATUS(completion_code), + SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR + ); + + sci_base_state_machine_change_state( + &sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED + ); + break; + } + + return status; +} + +static enum sci_status scic_sds_stp_request_pio_await_frame_frame_handler(struct scic_sds_request *sci_req, + u32 frame_index) +{ + struct scic_sds_controller *scic = sci_req->owning_controller; + struct scic_sds_stp_request *stp_req = &sci_req->stp.req; + struct isci_request *ireq = sci_req_to_ireq(sci_req); + struct sas_task *task = isci_request_access_task(ireq); + struct dev_to_host_fis *frame_header; + enum sci_status status; + u32 *frame_buffer; + + status = scic_sds_unsolicited_frame_control_get_header(&scic->uf_control, + frame_index, + (void **)&frame_header); + + if (status != SCI_SUCCESS) { + dev_err(scic_to_dev(scic), + "%s: SCIC IO Request 0x%p could not get frame header " + "for frame index %d, status %x\n", + __func__, stp_req, frame_index, status); + return status; + } + + switch (frame_header->fis_type) { + case FIS_PIO_SETUP: + /* Get from the frame buffer the PIO Setup Data */ + scic_sds_unsolicited_frame_control_get_buffer(&scic->uf_control, + frame_index, + (void **)&frame_buffer); + + /* Get the data from the PIO Setup The SCU Hardware returns + * first word in the frame_header and the rest of the data is in + * the frame buffer so we need to back up one dword + */ + + /* transfer_count: first 16bits in the 4th dword */ + stp_req->type.pio.pio_transfer_bytes = frame_buffer[3] & 0xffff; + + /* ending_status: 4th byte in the 3rd dword */ + stp_req->type.pio.ending_status = (frame_buffer[2] >> 24) & 0xff; + + scic_sds_controller_copy_sata_response(&sci_req->stp.rsp, + frame_header, + frame_buffer); + + sci_req->stp.rsp.status = stp_req->type.pio.ending_status; + + /* The next state is dependent on whether the + * request was PIO Data-in or Data out + */ + if (task->data_dir == DMA_FROM_DEVICE) { + sci_base_state_machine_change_state(&sci_req->started_substate_machine, + SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE); + } else if (task->data_dir == DMA_TO_DEVICE) { + /* Transmit data */ + status = scic_sds_stp_request_pio_data_out_transmit_data(sci_req); + if (status != SCI_SUCCESS) + break; + sci_base_state_machine_change_state(&sci_req->started_substate_machine, + SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE); + } + break; + case FIS_SETDEVBITS: + sci_base_state_machine_change_state(&sci_req->started_substate_machine, + SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE); + break; + case FIS_REGD2H: + if (frame_header->status & ATA_BUSY) { + /* Now why is the drive sending a D2H Register FIS when + * it is still busy? Do nothing since we are still in + * the right state. + */ + dev_dbg(scic_to_dev(scic), + "%s: SCIC PIO Request 0x%p received " + "D2H Register FIS with BSY status " + "0x%x\n", __func__, stp_req, + frame_header->status); + break; + } + + scic_sds_unsolicited_frame_control_get_buffer(&scic->uf_control, + frame_index, + (void **)&frame_buffer); + + scic_sds_controller_copy_sata_response(&sci_req->stp.req, + frame_header, + frame_buffer); + + scic_sds_request_set_status(sci_req, + SCU_TASK_DONE_CHECK_RESPONSE, + SCI_FAILURE_IO_RESPONSE_VALID); + + sci_base_state_machine_change_state(&sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + break; + default: + /* FIXME: what do we do here? */ + break; + } + + /* Frame is decoded return it to the controller */ + scic_sds_controller_release_frame(scic, frame_index); + + return status; +} + +static enum sci_status scic_sds_stp_request_pio_data_in_await_data_frame_handler(struct scic_sds_request *sci_req, + u32 frame_index) +{ + enum sci_status status; + struct dev_to_host_fis *frame_header; + struct sata_fis_data *frame_buffer; + struct scic_sds_stp_request *stp_req = &sci_req->stp.req; + struct scic_sds_controller *scic = sci_req->owning_controller; + + status = scic_sds_unsolicited_frame_control_get_header(&scic->uf_control, + frame_index, + (void **)&frame_header); + + if (status != SCI_SUCCESS) { + dev_err(scic_to_dev(scic), + "%s: SCIC IO Request 0x%p could not get frame header " + "for frame index %d, status %x\n", + __func__, stp_req, frame_index, status); + return status; + } + + if (frame_header->fis_type == FIS_DATA) { + if (stp_req->type.pio.request_current.sgl_pair == NULL) { + sci_req->saved_rx_frame_index = frame_index; + stp_req->type.pio.pio_transfer_bytes = 0; + } else { + scic_sds_unsolicited_frame_control_get_buffer(&scic->uf_control, + frame_index, + (void **)&frame_buffer); + + status = scic_sds_stp_request_pio_data_in_copy_data(stp_req, + (u8 *)frame_buffer); + + /* Frame is decoded return it to the controller */ + scic_sds_controller_release_frame(scic, frame_index); + } + + /* Check for the end of the transfer, are there more + * bytes remaining for this data transfer + */ + if (status != SCI_SUCCESS || + stp_req->type.pio.pio_transfer_bytes != 0) + return status; + + if ((stp_req->type.pio.ending_status & ATA_BUSY) == 0) { + scic_sds_request_set_status(sci_req, + SCU_TASK_DONE_CHECK_RESPONSE, + SCI_FAILURE_IO_RESPONSE_VALID); + + sci_base_state_machine_change_state(&sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + } else { + sci_base_state_machine_change_state(&sci_req->started_substate_machine, + SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE); + } + } else { + dev_err(scic_to_dev(scic), + "%s: SCIC PIO Request 0x%p received frame %d " + "with fis type 0x%02x when expecting a data " + "fis.\n", __func__, stp_req, frame_index, + frame_header->fis_type); + + scic_sds_request_set_status(sci_req, + SCU_TASK_DONE_GOOD, + SCI_FAILURE_IO_REQUIRES_SCSI_ABORT); + + sci_base_state_machine_change_state(&sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + + /* Frame is decoded return it to the controller */ + scic_sds_controller_release_frame(scic, frame_index); + } + + return status; +} + + +/** + * + * @sci_req: + * @completion_code: + * + * enum sci_status + */ +static enum sci_status scic_sds_stp_request_pio_data_out_await_data_transmit_completion_tc_completion_handler( + + struct scic_sds_request *sci_req, + u32 completion_code) +{ + enum sci_status status = SCI_SUCCESS; + bool all_frames_transferred = false; + struct scic_sds_stp_request *stp_req = &sci_req->stp.req; + + switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): + /* Transmit data */ + if (stp_req->type.pio.pio_transfer_bytes != 0) { + status = scic_sds_stp_request_pio_data_out_transmit_data(sci_req); + if (status == SCI_SUCCESS) { + if (stp_req->type.pio.pio_transfer_bytes == 0) + all_frames_transferred = true; + } + } else if (stp_req->type.pio.pio_transfer_bytes == 0) { + /* + * this will happen if the all data is written at the + * first time after the pio setup fis is received + */ + all_frames_transferred = true; + } + + /* all data transferred. */ + if (all_frames_transferred) { + /* + * Change the state to SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_FRAME_SUBSTATE + * and wait for PIO_SETUP fis / or D2H REg fis. */ + sci_base_state_machine_change_state( + &sci_req->started_substate_machine, + SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE + ); + } + break; + + default: + /* + * All other completion status cause the IO to be complete. If a NAK + * was received, then it is up to the user to retry the request. */ + scic_sds_request_set_status( + sci_req, + SCU_NORMALIZE_COMPLETION_STATUS(completion_code), + SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR + ); + + sci_base_state_machine_change_state( + &sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED + ); + break; + } + + return status; +} + +/** + * + * @request: This is the request which is receiving the event. + * @event_code: This is the event code that the request on which the request is + * expected to take action. + * + * This method will handle any link layer events while waiting for the data + * frame. enum sci_status SCI_SUCCESS SCI_FAILURE + */ +static enum sci_status scic_sds_stp_request_pio_data_in_await_data_event_handler( + struct scic_sds_request *request, + u32 event_code) +{ + enum sci_status status; + + switch (scu_get_event_specifier(event_code)) { + case SCU_TASK_DONE_CRC_ERR << SCU_EVENT_SPECIFIC_CODE_SHIFT: + /* + * We are waiting for data and the SCU has R_ERR the data frame. + * Go back to waiting for the D2H Register FIS */ + sci_base_state_machine_change_state( + &request->started_substate_machine, + SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE + ); + + status = SCI_SUCCESS; + break; + + default: + dev_err(scic_to_dev(request->owning_controller), + "%s: SCIC PIO Request 0x%p received unexpected " + "event 0x%08x\n", + __func__, request, event_code); + + /* / @todo Should we fail the PIO request when we get an unexpected event? */ + status = SCI_FAILURE; + break; + } + + return status; +} + +/* --------------------------------------------------------------------------- */ + +static const struct scic_sds_io_request_state_handler scic_sds_stp_request_started_pio_substate_handler_table[] = { + [SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE] = { + .abort_handler = scic_sds_request_started_state_abort_handler, + .tc_completion_handler = scic_sds_stp_request_pio_await_h2d_completion_tc_completion_handler, + }, + [SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE] = { + .abort_handler = scic_sds_request_started_state_abort_handler, + .frame_handler = scic_sds_stp_request_pio_await_frame_frame_handler + }, + [SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE] = { + .abort_handler = scic_sds_request_started_state_abort_handler, + .event_handler = scic_sds_stp_request_pio_data_in_await_data_event_handler, + .frame_handler = scic_sds_stp_request_pio_data_in_await_data_frame_handler + }, + [SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE] = { + .abort_handler = scic_sds_request_started_state_abort_handler, + .tc_completion_handler = scic_sds_stp_request_pio_data_out_await_data_transmit_completion_tc_completion_handler, + } +}; + +static void scic_sds_stp_request_started_pio_await_h2d_completion_enter( + void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_stp_request_started_pio_substate_handler_table, + SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE + ); + + scic_sds_remote_device_set_working_request( + sci_req->target_device, sci_req); +} + +static void scic_sds_stp_request_started_pio_await_frame_enter(void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_stp_request_started_pio_substate_handler_table, + SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE + ); +} + +static void scic_sds_stp_request_started_pio_data_in_await_data_enter( + void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_stp_request_started_pio_substate_handler_table, + SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE + ); +} + +static void scic_sds_stp_request_started_pio_data_out_transmit_data_enter( + void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_stp_request_started_pio_substate_handler_table, + SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE + ); +} + +/* --------------------------------------------------------------------------- */ + +static const struct sci_base_state scic_sds_stp_request_started_pio_substate_table[] = { + [SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE] = { + .enter_state = scic_sds_stp_request_started_pio_await_h2d_completion_enter, + }, + [SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE] = { + .enter_state = scic_sds_stp_request_started_pio_await_frame_enter, + }, + [SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE] = { + .enter_state = scic_sds_stp_request_started_pio_data_in_await_data_enter, + }, + [SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE] = { + .enter_state = scic_sds_stp_request_started_pio_data_out_transmit_data_enter, + } +}; + +enum sci_status +scic_sds_stp_pio_request_construct(struct scic_sds_request *sci_req, + bool copy_rx_frame) +{ + struct scic_sds_stp_request *stp_req = &sci_req->stp.req; + struct scic_sds_stp_pio_request *pio = &stp_req->type.pio; + + scic_sds_stp_non_ncq_request_construct(sci_req); + + scu_stp_raw_request_construct_task_context(stp_req, + sci_req->task_context_buffer); + + pio->current_transfer_bytes = 0; + pio->ending_error = 0; + pio->ending_status = 0; + + pio->request_current.sgl_offset = 0; + pio->request_current.sgl_set = SCU_SGL_ELEMENT_PAIR_A; + + if (copy_rx_frame) { + scic_sds_request_build_sgl(sci_req); + /* Since the IO request copy of the TC contains the same data as + * the actual TC this pointer is vaild for either. + */ + pio->request_current.sgl_pair = &sci_req->task_context_buffer->sgl_pair_ab; + } else { + /* The user does not want the data copied to the SGL buffer location */ + pio->request_current.sgl_pair = NULL; + } + + sci_base_state_machine_construct(&sci_req->started_substate_machine, + sci_req, + scic_sds_stp_request_started_pio_substate_table, + SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE); + + return SCI_SUCCESS; +} + +static void scic_sds_stp_request_udma_complete_request( + struct scic_sds_request *request, + u32 scu_status, + enum sci_status sci_status) +{ + scic_sds_request_set_status(request, scu_status, sci_status); + sci_base_state_machine_change_state(&request->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); +} + +static enum sci_status scic_sds_stp_request_udma_general_frame_handler(struct scic_sds_request *sci_req, + u32 frame_index) +{ + struct scic_sds_controller *scic = sci_req->owning_controller; + struct dev_to_host_fis *frame_header; + enum sci_status status; + u32 *frame_buffer; + + status = scic_sds_unsolicited_frame_control_get_header(&scic->uf_control, + frame_index, + (void **)&frame_header); + + if ((status == SCI_SUCCESS) && + (frame_header->fis_type == FIS_REGD2H)) { + scic_sds_unsolicited_frame_control_get_buffer(&scic->uf_control, + frame_index, + (void **)&frame_buffer); + + scic_sds_controller_copy_sata_response(&sci_req->stp.rsp, + frame_header, + frame_buffer); + } + + scic_sds_controller_release_frame(scic, frame_index); + + return status; +} + +static enum sci_status scic_sds_stp_request_udma_await_tc_completion_tc_completion_handler( + struct scic_sds_request *sci_req, + u32 completion_code) +{ + enum sci_status status = SCI_SUCCESS; + + switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): + scic_sds_stp_request_udma_complete_request(sci_req, + SCU_TASK_DONE_GOOD, + SCI_SUCCESS); + break; + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_FIS): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR): + /* + * We must check ther response buffer to see if the D2H Register FIS was + * received before we got the TC completion. */ + if (sci_req->stp.rsp.fis_type == FIS_REGD2H) { + scic_sds_remote_device_suspend(sci_req->target_device, + SCU_EVENT_SPECIFIC(SCU_NORMALIZE_COMPLETION_STATUS(completion_code))); + + scic_sds_stp_request_udma_complete_request(sci_req, + SCU_TASK_DONE_CHECK_RESPONSE, + SCI_FAILURE_IO_RESPONSE_VALID); + } else { + /* + * If we have an error completion status for the TC then we can expect a + * D2H register FIS from the device so we must change state to wait for it */ + sci_base_state_machine_change_state(&sci_req->started_substate_machine, + SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE); + } + break; + + /* + * / @todo Check to see if any of these completion status need to wait for + * / the device to host register fis. */ + /* / @todo We can retry the command for SCU_TASK_DONE_CMD_LL_R_ERR - this comes only for B0 */ + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_INV_FIS_LEN): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_MAX_PLD_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_R_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CMD_LL_R_ERR): + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CRC_ERR): + scic_sds_remote_device_suspend(sci_req->target_device, + SCU_EVENT_SPECIFIC(SCU_NORMALIZE_COMPLETION_STATUS(completion_code))); + /* Fall through to the default case */ + default: + /* All other completion status cause the IO to be complete. */ + scic_sds_stp_request_udma_complete_request(sci_req, + SCU_NORMALIZE_COMPLETION_STATUS(completion_code), + SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR); + break; + } + + return status; +} + +static enum sci_status scic_sds_stp_request_udma_await_d2h_reg_fis_frame_handler( + struct scic_sds_request *sci_req, + u32 frame_index) +{ + enum sci_status status; + + /* Use the general frame handler to copy the resposne data */ + status = scic_sds_stp_request_udma_general_frame_handler(sci_req, frame_index); + + if (status != SCI_SUCCESS) + return status; + + scic_sds_stp_request_udma_complete_request(sci_req, + SCU_TASK_DONE_CHECK_RESPONSE, + SCI_FAILURE_IO_RESPONSE_VALID); + + return status; +} + +/* --------------------------------------------------------------------------- */ + +static const struct scic_sds_io_request_state_handler scic_sds_stp_request_started_udma_substate_handler_table[] = { + [SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE] = { + .abort_handler = scic_sds_request_started_state_abort_handler, + .tc_completion_handler = scic_sds_stp_request_udma_await_tc_completion_tc_completion_handler, + .frame_handler = scic_sds_stp_request_udma_general_frame_handler, + }, + [SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE] = { + .abort_handler = scic_sds_request_started_state_abort_handler, + .frame_handler = scic_sds_stp_request_udma_await_d2h_reg_fis_frame_handler, + }, +}; + +static void scic_sds_stp_request_started_udma_await_tc_completion_enter( + void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_stp_request_started_udma_substate_handler_table, + SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE + ); +} + +/** + * + * + * This state is entered when there is an TC completion failure. The hardware + * received an unexpected condition while processing the IO request and now + * will UF the D2H register FIS to complete the IO. + */ +static void scic_sds_stp_request_started_udma_await_d2h_reg_fis_enter( + void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_stp_request_started_udma_substate_handler_table, + SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE + ); +} + +/* --------------------------------------------------------------------------- */ + +static const struct sci_base_state scic_sds_stp_request_started_udma_substate_table[] = { + [SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE] = { + .enter_state = scic_sds_stp_request_started_udma_await_tc_completion_enter, + }, + [SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE] = { + .enter_state = scic_sds_stp_request_started_udma_await_d2h_reg_fis_enter, + }, +}; + +enum sci_status scic_sds_stp_udma_request_construct(struct scic_sds_request *sci_req, + u32 len, + enum dma_data_direction dir) +{ + scic_sds_stp_non_ncq_request_construct(sci_req); + + scic_sds_stp_optimized_request_construct(sci_req, SCU_TASK_TYPE_DMA_IN, + len, dir); + + sci_base_state_machine_construct( + &sci_req->started_substate_machine, + sci_req, + scic_sds_stp_request_started_udma_substate_table, + SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE + ); + + return SCI_SUCCESS; +} + +/** + * + * @sci_req: + * @completion_code: + * + * This method processes a TC completion. The expected TC completion is for + * the transmission of the H2D register FIS containing the SATA/STP non-data + * request. This method always successfully processes the TC completion. + * SCI_SUCCESS This value is always returned. + */ +static enum sci_status scic_sds_stp_request_soft_reset_await_h2d_asserted_tc_completion_handler( + struct scic_sds_request *sci_req, + u32 completion_code) +{ + switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): + scic_sds_request_set_status( + sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS + ); + + sci_base_state_machine_change_state( + &sci_req->started_substate_machine, + SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE + ); + break; + + default: + /* + * All other completion status cause the IO to be complete. If a NAK + * was received, then it is up to the user to retry the request. */ + scic_sds_request_set_status( + sci_req, + SCU_NORMALIZE_COMPLETION_STATUS(completion_code), + SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR + ); + + sci_base_state_machine_change_state( + &sci_req->state_machine, SCI_BASE_REQUEST_STATE_COMPLETED); + break; + } + + return SCI_SUCCESS; +} + +/** + * + * @sci_req: + * @completion_code: + * + * This method processes a TC completion. The expected TC completion is for + * the transmission of the H2D register FIS containing the SATA/STP non-data + * request. This method always successfully processes the TC completion. + * SCI_SUCCESS This value is always returned. + */ +static enum sci_status scic_sds_stp_request_soft_reset_await_h2d_diagnostic_tc_completion_handler( + struct scic_sds_request *sci_req, + u32 completion_code) +{ + switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { + case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): + scic_sds_request_set_status( + sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS + ); + + sci_base_state_machine_change_state( + &sci_req->started_substate_machine, + SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE + ); + break; + + default: + /* + * All other completion status cause the IO to be complete. If a NAK + * was received, then it is up to the user to retry the request. */ + scic_sds_request_set_status( + sci_req, + SCU_NORMALIZE_COMPLETION_STATUS(completion_code), + SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR + ); + + sci_base_state_machine_change_state(&sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + break; + } + + return SCI_SUCCESS; +} + +/** + * + * @request: This parameter specifies the request for which a frame has been + * received. + * @frame_index: This parameter specifies the index of the frame that has been + * received. + * + * This method processes frames received from the target while waiting for a + * device to host register FIS. If a non-register FIS is received during this + * time, it is treated as a protocol violation from an IO perspective. Indicate + * if the received frame was processed successfully. + */ +static enum sci_status scic_sds_stp_request_soft_reset_await_d2h_frame_handler( + struct scic_sds_request *sci_req, + u32 frame_index) +{ + enum sci_status status; + struct dev_to_host_fis *frame_header; + u32 *frame_buffer; + struct scic_sds_stp_request *stp_req = &sci_req->stp.req; + struct scic_sds_controller *scic = sci_req->owning_controller; + + status = scic_sds_unsolicited_frame_control_get_header(&scic->uf_control, + frame_index, + (void **)&frame_header); + if (status != SCI_SUCCESS) { + dev_err(scic_to_dev(scic), + "%s: SCIC IO Request 0x%p could not get frame header " + "for frame index %d, status %x\n", + __func__, stp_req, frame_index, status); + return status; + } + + switch (frame_header->fis_type) { + case FIS_REGD2H: + scic_sds_unsolicited_frame_control_get_buffer(&scic->uf_control, + frame_index, + (void **)&frame_buffer); + + scic_sds_controller_copy_sata_response(&sci_req->stp.rsp, + frame_header, + frame_buffer); + + /* The command has completed with error */ + scic_sds_request_set_status(sci_req, + SCU_TASK_DONE_CHECK_RESPONSE, + SCI_FAILURE_IO_RESPONSE_VALID); + break; + + default: + dev_warn(scic_to_dev(scic), + "%s: IO Request:0x%p Frame Id:%d protocol " + "violation occurred\n", __func__, stp_req, + frame_index); + + scic_sds_request_set_status(sci_req, SCU_TASK_DONE_UNEXP_FIS, + SCI_FAILURE_PROTOCOL_VIOLATION); + break; + } + + sci_base_state_machine_change_state(&sci_req->state_machine, + SCI_BASE_REQUEST_STATE_COMPLETED); + + /* Frame has been decoded return it to the controller */ + scic_sds_controller_release_frame(scic, frame_index); + + return status; +} + +/* --------------------------------------------------------------------------- */ + +static const struct scic_sds_io_request_state_handler scic_sds_stp_request_started_soft_reset_substate_handler_table[] = { + [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE] = { + .abort_handler = scic_sds_request_started_state_abort_handler, + .tc_completion_handler = scic_sds_stp_request_soft_reset_await_h2d_asserted_tc_completion_handler, + }, + [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE] = { + .abort_handler = scic_sds_request_started_state_abort_handler, + .tc_completion_handler = scic_sds_stp_request_soft_reset_await_h2d_diagnostic_tc_completion_handler, + }, + [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE] = { + .abort_handler = scic_sds_request_started_state_abort_handler, + .frame_handler = scic_sds_stp_request_soft_reset_await_d2h_frame_handler, + }, +}; + +static void scic_sds_stp_request_started_soft_reset_await_h2d_asserted_completion_enter( + void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_stp_request_started_soft_reset_substate_handler_table, + SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE + ); + + scic_sds_remote_device_set_working_request( + sci_req->target_device, sci_req + ); +} + +static void scic_sds_stp_request_started_soft_reset_await_h2d_diagnostic_completion_enter( + void *object) +{ + struct scic_sds_request *sci_req = object; + struct scu_task_context *task_context; + struct host_to_dev_fis *h2d_fis; + enum sci_status status; + + /* Clear the SRST bit */ + h2d_fis = &sci_req->stp.cmd; + h2d_fis->control = 0; + + /* Clear the TC control bit */ + task_context = scic_sds_controller_get_task_context_buffer( + sci_req->owning_controller, sci_req->io_tag); + task_context->control_frame = 0; + + status = scic_controller_continue_io(sci_req); + if (status == SCI_SUCCESS) { + SET_STATE_HANDLER( + sci_req, + scic_sds_stp_request_started_soft_reset_substate_handler_table, + SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE + ); + } +} + +static void scic_sds_stp_request_started_soft_reset_await_d2h_response_enter( + void *object) +{ + struct scic_sds_request *sci_req = object; + + SET_STATE_HANDLER( + sci_req, + scic_sds_stp_request_started_soft_reset_substate_handler_table, + SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE + ); +} + +static const struct sci_base_state scic_sds_stp_request_started_soft_reset_substate_table[] = { + [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE] = { + .enter_state = scic_sds_stp_request_started_soft_reset_await_h2d_asserted_completion_enter, + }, + [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE] = { + .enter_state = scic_sds_stp_request_started_soft_reset_await_h2d_diagnostic_completion_enter, + }, + [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE] = { + .enter_state = scic_sds_stp_request_started_soft_reset_await_d2h_response_enter, + }, +}; + +enum sci_status scic_sds_stp_soft_reset_request_construct(struct scic_sds_request *sci_req) +{ + struct scic_sds_stp_request *stp_req = &sci_req->stp.req; + + scic_sds_stp_non_ncq_request_construct(sci_req); + + /* Build the STP task context structure */ + scu_stp_raw_request_construct_task_context(stp_req, sci_req->task_context_buffer); + + sci_base_state_machine_construct(&sci_req->started_substate_machine, + sci_req, + scic_sds_stp_request_started_soft_reset_substate_table, + SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE); + + return SCI_SUCCESS; +} diff --git a/drivers/scsi/isci/stp_request.h b/drivers/scsi/isci/stp_request.h new file mode 100644 index 000000000000..eb14874ceda3 --- /dev/null +++ b/drivers/scsi/isci/stp_request.h @@ -0,0 +1,195 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SCIC_SDS_STP_REQUEST_T_ +#define _SCIC_SDS_STP_REQUEST_T_ + +#include +#include + +struct scic_sds_stp_request { + union { + u32 ncq; + + u32 udma; + + struct scic_sds_stp_pio_request { + /** + * Total transfer for the entire PIO request recorded at request constuction + * time. + * + * @todo Should we just decrement this value for each byte of data transitted + * or received to elemenate the current_transfer_bytes field? + */ + u32 total_transfer_bytes; + + /** + * Total number of bytes received/transmitted in data frames since the start + * of the IO request. At the end of the IO request this should equal the + * total_transfer_bytes. + */ + u32 current_transfer_bytes; + + /** + * The number of bytes requested in the in the PIO setup. + */ + u32 pio_transfer_bytes; + + /** + * PIO Setup ending status value to tell us if we need to wait for another FIS + * or if the transfer is complete. On the receipt of a D2H FIS this will be + * the status field of that FIS. + */ + u8 ending_status; + + /** + * On receipt of a D2H FIS this will be the ending error field if the + * ending_status has the SATA_STATUS_ERR bit set. + */ + u8 ending_error; + + struct scic_sds_request_pio_sgl { + struct scu_sgl_element_pair *sgl_pair; + u8 sgl_set; + u32 sgl_offset; + } request_current; + } pio; + + struct { + /** + * The number of bytes requested in the PIO setup before CDB data frame. + */ + u32 device_preferred_cdb_length; + } packet; + } type; +}; + +/** + * enum scic_sds_stp_request_started_udma_substates - This enumeration depicts + * the various sub-states associated with a SATA/STP UDMA protocol operation. + * + * + */ +enum scic_sds_stp_request_started_udma_substates { + SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE, + SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE, +}; + +/** + * enum scic_sds_stp_request_started_non_data_substates - This enumeration + * depicts the various sub-states associated with a SATA/STP non-data + * protocol operation. + * + * + */ +enum scic_sds_stp_request_started_non_data_substates { + SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE, + SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE, +}; + +/** + * enum scic_sds_stp_request_started_soft_reset_substates - THis enumeration + * depicts the various sub-states associated with a SATA/STP soft reset + * operation. + * + * + */ +enum scic_sds_stp_request_started_soft_reset_substates { + SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE, + SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE, + SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE, +}; + +/* This is the enumeration of the SATA PIO DATA IN started substate machine. */ +enum _scic_sds_stp_request_started_pio_substates { + /** + * While in this state the IO request object is waiting for the TC completion + * notification for the H2D Register FIS + */ + SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE, + + /** + * While in this state the IO request object is waiting for either a PIO Setup + * FIS or a D2H register FIS. The type of frame received is based on the + * result of the prior frame and line conditions. + */ + SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE, + + /** + * While in this state the IO request object is waiting for a DATA frame from + * the device. + */ + SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE, + + /** + * While in this state the IO request object is waiting to transmit the next data + * frame to the device. + */ + SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE, +}; + +struct scic_sds_request; + +enum sci_status scic_sds_stp_pio_request_construct(struct scic_sds_request *sci_req, + bool copy_rx_frame); +enum sci_status scic_sds_stp_udma_request_construct(struct scic_sds_request *sci_req, + u32 transfer_length, + enum dma_data_direction dir); +enum sci_status scic_sds_stp_non_data_request_construct(struct scic_sds_request *sci_req); +enum sci_status scic_sds_stp_soft_reset_request_construct(struct scic_sds_request *sci_req); +enum sci_status scic_sds_stp_ncq_request_construct(struct scic_sds_request *sci_req, + u32 transfer_length, + enum dma_data_direction dir); +#endif /* _SCIC_SDS_STP_REQUEST_T_ */ diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 2a8603881929..078e2ee4f4be 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -56,15 +56,12 @@ #include #include #include "sas.h" -#include "scic_task_request.h" -#include "scic_io_request.h" #include "remote_device.h" #include "remote_node_context.h" #include "isci.h" #include "request.h" #include "sata.h" #include "task.h" -#include "scic_sds_request.h" #include "timers.h" /** diff --git a/drivers/scsi/isci/unsolicited_frame_control.c b/drivers/scsi/isci/unsolicited_frame_control.c index 8d68dcc52bc1..12e676346386 100644 --- a/drivers/scsi/isci/unsolicited_frame_control.c +++ b/drivers/scsi/isci/unsolicited_frame_control.c @@ -56,7 +56,6 @@ #include "host.h" #include "unsolicited_frame_control.h" #include "registers.h" -#include "sci_util.h" /** * This method will program the unsolicited frames (UFs) into the UF address @@ -93,10 +92,8 @@ static void scic_sds_unsolicited_frame_control_construct_frames( for (index = 0; index < unused_uf_header_entries; index++) { uf = &uf_control->buffers.array[index]; - sci_cb_make_physical_address( - uf_control->address_table.array[index], 0, 0 - ); uf->buffer = NULL; + uf_control->address_table.array[index] = 0; uf->header = &uf_control->headers.array[index]; uf->state = UNSOLICITED_FRAME_EMPTY; } -- cgit v1.2.3-58-ga151