16f231ddaSDan Williams /* 26f231ddaSDan Williams * This file is provided under a dual BSD/GPLv2 license. When using or 36f231ddaSDan Williams * redistributing this file, you may do so under either license. 46f231ddaSDan Williams * 56f231ddaSDan Williams * GPL LICENSE SUMMARY 66f231ddaSDan Williams * 76f231ddaSDan Williams * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 86f231ddaSDan Williams * 96f231ddaSDan Williams * This program is free software; you can redistribute it and/or modify 106f231ddaSDan Williams * it under the terms of version 2 of the GNU General Public License as 116f231ddaSDan Williams * published by the Free Software Foundation. 126f231ddaSDan Williams * 136f231ddaSDan Williams * This program is distributed in the hope that it will be useful, but 146f231ddaSDan Williams * WITHOUT ANY WARRANTY; without even the implied warranty of 156f231ddaSDan Williams * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 166f231ddaSDan Williams * General Public License for more details. 176f231ddaSDan Williams * 186f231ddaSDan Williams * You should have received a copy of the GNU General Public License 196f231ddaSDan Williams * along with this program; if not, write to the Free Software 206f231ddaSDan Williams * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 216f231ddaSDan Williams * The full GNU General Public License is included in this distribution 226f231ddaSDan Williams * in the file called LICENSE.GPL. 236f231ddaSDan Williams * 246f231ddaSDan Williams * BSD LICENSE 256f231ddaSDan Williams * 266f231ddaSDan Williams * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 276f231ddaSDan Williams * All rights reserved. 286f231ddaSDan Williams * 296f231ddaSDan Williams * Redistribution and use in source and binary forms, with or without 306f231ddaSDan Williams * modification, are permitted provided that the following conditions 316f231ddaSDan Williams * are met: 326f231ddaSDan Williams * 336f231ddaSDan Williams * * Redistributions of source code must retain the above copyright 346f231ddaSDan Williams * notice, this list of conditions and the following disclaimer. 356f231ddaSDan Williams * * Redistributions in binary form must reproduce the above copyright 366f231ddaSDan Williams * notice, this list of conditions and the following disclaimer in 376f231ddaSDan Williams * the documentation and/or other materials provided with the 386f231ddaSDan Williams * distribution. 396f231ddaSDan Williams * * Neither the name of Intel Corporation nor the names of its 406f231ddaSDan Williams * contributors may be used to endorse or promote products derived 416f231ddaSDan Williams * from this software without specific prior written permission. 426f231ddaSDan Williams * 436f231ddaSDan Williams * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 446f231ddaSDan Williams * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 456f231ddaSDan Williams * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 466f231ddaSDan Williams * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 476f231ddaSDan Williams * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 486f231ddaSDan Williams * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 496f231ddaSDan Williams * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 506f231ddaSDan Williams * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 516f231ddaSDan Williams * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 526f231ddaSDan Williams * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 536f231ddaSDan Williams * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 546f231ddaSDan Williams */ 556f231ddaSDan Williams 560d84366fSDan Williams #ifndef _ISCI_REQUEST_H_ 576f231ddaSDan Williams #define _ISCI_REQUEST_H_ 586f231ddaSDan Williams 596f231ddaSDan Williams #include "isci.h" 600d84366fSDan Williams #include "scic_sds_request.h" 616f231ddaSDan Williams 626f231ddaSDan Williams /** 636f231ddaSDan Williams * struct isci_request_status - This enum defines the possible states of an I/O 646f231ddaSDan Williams * request. 656f231ddaSDan Williams * 666f231ddaSDan Williams * 676f231ddaSDan Williams */ 686f231ddaSDan Williams enum isci_request_status { 696f231ddaSDan Williams unallocated = 0x00, 706f231ddaSDan Williams allocated = 0x01, 716f231ddaSDan Williams started = 0x02, 726f231ddaSDan Williams completed = 0x03, 736f231ddaSDan Williams aborting = 0x04, 746f231ddaSDan Williams aborted = 0x05, 754dc043c4SJeff Skirvin terminating = 0x06, 764dc043c4SJeff Skirvin dead = 0x07 776f231ddaSDan Williams }; 786f231ddaSDan Williams 796f231ddaSDan Williams enum task_type { 806f231ddaSDan Williams io_task = 0, 816f231ddaSDan Williams tmf_task = 1 826f231ddaSDan Williams }; 836f231ddaSDan Williams 846f231ddaSDan Williams struct isci_request { 856f231ddaSDan Williams enum isci_request_status status; 866f231ddaSDan Williams enum task_type ttype; 876f231ddaSDan Williams unsigned short io_tag; 886f231ddaSDan Williams bool complete_in_target; 89*67ea838dSDan Williams bool terminated; 906f231ddaSDan Williams 916f231ddaSDan Williams union ttype_ptr_union { 926f231ddaSDan Williams struct sas_task *io_task_ptr; /* When ttype==io_task */ 936f231ddaSDan Williams struct isci_tmf *tmf_task_ptr; /* When ttype==tmf_task */ 946f231ddaSDan Williams } ttype_ptr; 956f231ddaSDan Williams struct isci_host *isci_host; 966f231ddaSDan Williams struct isci_remote_device *isci_device; 976f231ddaSDan Williams /* For use in the requests_to_{complete|abort} lists: */ 986f231ddaSDan Williams struct list_head completed_node; 996f231ddaSDan Williams /* For use in the reqs_in_process list: */ 1006f231ddaSDan Williams struct list_head dev_node; 1016f231ddaSDan Williams spinlock_t state_lock; 1026f231ddaSDan Williams dma_addr_t request_daddr; 1036f231ddaSDan Williams dma_addr_t zero_scatter_daddr; 1046f231ddaSDan Williams 1056f231ddaSDan Williams unsigned int num_sg_entries; /* returned by pci_alloc_sg */ 1066f231ddaSDan Williams 1076f231ddaSDan Williams /** Note: "io_request_completion" is completed in two different ways 1086f231ddaSDan Williams * depending on whether this is a TMF or regular request. 1096f231ddaSDan Williams * - TMF requests are completed in the thread that started them; 1106f231ddaSDan Williams * - regular requests are completed in the request completion callback 1116f231ddaSDan Williams * function. 1126f231ddaSDan Williams * This difference in operation allows the aborter of a TMF request 1136f231ddaSDan Williams * to be sure that once the TMF request completes, the I/O that the 1146f231ddaSDan Williams * TMF was aborting is guaranteed to have completed. 1156f231ddaSDan Williams */ 1166f231ddaSDan Williams struct completion *io_request_completion; 117*67ea838dSDan Williams struct scic_sds_request sci; 1186f231ddaSDan Williams }; 1196f231ddaSDan Williams 120*67ea838dSDan Williams static inline struct isci_request *sci_req_to_ireq(struct scic_sds_request *sci_req) 121*67ea838dSDan Williams { 122*67ea838dSDan Williams struct isci_request *ireq = container_of(sci_req, typeof(*ireq), sci); 123*67ea838dSDan Williams 124*67ea838dSDan Williams return ireq; 125*67ea838dSDan Williams } 126*67ea838dSDan Williams 1276f231ddaSDan Williams /** 1286f231ddaSDan Williams * This function gets the status of the request object. 1296f231ddaSDan Williams * @request: This parameter points to the isci_request object 1306f231ddaSDan Williams * 1316f231ddaSDan Williams * status of the object as a isci_request_status enum. 1326f231ddaSDan Williams */ 1336f231ddaSDan Williams static inline 1346f231ddaSDan Williams enum isci_request_status isci_request_get_state( 1356f231ddaSDan Williams struct isci_request *isci_request) 1366f231ddaSDan Williams { 1376f231ddaSDan Williams BUG_ON(isci_request == NULL); 1386f231ddaSDan Williams 1396f231ddaSDan Williams /*probably a bad sign... */ 1406f231ddaSDan Williams if (isci_request->status == unallocated) 1416f231ddaSDan Williams dev_warn(&isci_request->isci_host->pdev->dev, 1426f231ddaSDan Williams "%s: isci_request->status == unallocated\n", 1436f231ddaSDan Williams __func__); 1446f231ddaSDan Williams 1456f231ddaSDan Williams return isci_request->status; 1466f231ddaSDan Williams } 1476f231ddaSDan Williams 1486f231ddaSDan Williams 1496f231ddaSDan Williams /** 1506f231ddaSDan Williams * isci_request_change_state() - This function sets the status of the request 1516f231ddaSDan Williams * object. 1526f231ddaSDan Williams * @request: This parameter points to the isci_request object 1536f231ddaSDan Williams * @status: This Parameter is the new status of the object 1546f231ddaSDan Williams * 1556f231ddaSDan Williams */ 1566f231ddaSDan Williams static inline enum isci_request_status isci_request_change_state( 1576f231ddaSDan Williams struct isci_request *isci_request, 1586f231ddaSDan Williams enum isci_request_status status) 1596f231ddaSDan Williams { 1606f231ddaSDan Williams enum isci_request_status old_state; 1616f231ddaSDan Williams unsigned long flags; 1626f231ddaSDan Williams 1636f231ddaSDan Williams dev_dbg(&isci_request->isci_host->pdev->dev, 1646f231ddaSDan Williams "%s: isci_request = %p, state = 0x%x\n", 1656f231ddaSDan Williams __func__, 1666f231ddaSDan Williams isci_request, 1676f231ddaSDan Williams status); 1686f231ddaSDan Williams 1696f231ddaSDan Williams BUG_ON(isci_request == NULL); 1706f231ddaSDan Williams 1716f231ddaSDan Williams spin_lock_irqsave(&isci_request->state_lock, flags); 1726f231ddaSDan Williams old_state = isci_request->status; 1736f231ddaSDan Williams isci_request->status = status; 1746f231ddaSDan Williams spin_unlock_irqrestore(&isci_request->state_lock, flags); 1756f231ddaSDan Williams 1766f231ddaSDan Williams return old_state; 1776f231ddaSDan Williams } 1786f231ddaSDan Williams 1796f231ddaSDan Williams /** 1806f231ddaSDan Williams * isci_request_change_started_to_newstate() - This function sets the status of 1816f231ddaSDan Williams * the request object. 1826f231ddaSDan Williams * @request: This parameter points to the isci_request object 1836f231ddaSDan Williams * @status: This Parameter is the new status of the object 1846f231ddaSDan Williams * 1856f231ddaSDan Williams * state previous to any change. 1866f231ddaSDan Williams */ 1876f231ddaSDan Williams static inline enum isci_request_status isci_request_change_started_to_newstate( 1886f231ddaSDan Williams struct isci_request *isci_request, 1896f231ddaSDan Williams struct completion *completion_ptr, 1906f231ddaSDan Williams enum isci_request_status newstate) 1916f231ddaSDan Williams { 1926f231ddaSDan Williams enum isci_request_status old_state; 1936f231ddaSDan Williams unsigned long flags; 1946f231ddaSDan Williams 1956f231ddaSDan Williams spin_lock_irqsave(&isci_request->state_lock, flags); 1966f231ddaSDan Williams 1976f231ddaSDan Williams old_state = isci_request->status; 1986f231ddaSDan Williams 199f219f010SJeff Skirvin if (old_state == started || old_state == aborting) { 2006f231ddaSDan Williams BUG_ON(isci_request->io_request_completion != NULL); 2016f231ddaSDan Williams 2026f231ddaSDan Williams isci_request->io_request_completion = completion_ptr; 2036f231ddaSDan Williams isci_request->status = newstate; 2046f231ddaSDan Williams } 2056f231ddaSDan Williams spin_unlock_irqrestore(&isci_request->state_lock, flags); 2066f231ddaSDan Williams 2076f231ddaSDan Williams dev_dbg(&isci_request->isci_host->pdev->dev, 2086f231ddaSDan Williams "%s: isci_request = %p, old_state = 0x%x\n", 2096f231ddaSDan Williams __func__, 2106f231ddaSDan Williams isci_request, 2116f231ddaSDan Williams old_state); 2126f231ddaSDan Williams 2136f231ddaSDan Williams return old_state; 2146f231ddaSDan Williams } 2156f231ddaSDan Williams 2166f231ddaSDan Williams /** 2176f231ddaSDan Williams * isci_request_change_started_to_aborted() - This function sets the status of 2186f231ddaSDan Williams * the request object. 2196f231ddaSDan Williams * @request: This parameter points to the isci_request object 2206f231ddaSDan Williams * @completion_ptr: This parameter is saved as the kernel completion structure 2216f231ddaSDan Williams * signalled when the old request completes. 2226f231ddaSDan Williams * 2236f231ddaSDan Williams * state previous to any change. 2246f231ddaSDan Williams */ 2256f231ddaSDan Williams static inline enum isci_request_status isci_request_change_started_to_aborted( 2266f231ddaSDan Williams struct isci_request *isci_request, 2276f231ddaSDan Williams struct completion *completion_ptr) 2286f231ddaSDan Williams { 2296f231ddaSDan Williams return isci_request_change_started_to_newstate( 2306f231ddaSDan Williams isci_request, completion_ptr, aborted 2316f231ddaSDan Williams ); 2326f231ddaSDan Williams } 2336f231ddaSDan Williams /** 2346f231ddaSDan Williams * isci_request_free() - This function frees the request object. 2356f231ddaSDan Williams * @isci_host: This parameter specifies the ISCI host object 2366f231ddaSDan Williams * @isci_request: This parameter points to the isci_request object 2376f231ddaSDan Williams * 2386f231ddaSDan Williams */ 2396f231ddaSDan Williams static inline void isci_request_free( 2406f231ddaSDan Williams struct isci_host *isci_host, 2416f231ddaSDan Williams struct isci_request *isci_request) 2426f231ddaSDan Williams { 2436cb4d6b3SBartosz Barcinski if (!isci_request) 2446cb4d6b3SBartosz Barcinski return; 2456f231ddaSDan Williams 2466f231ddaSDan Williams /* release the dma memory if we fail. */ 2476f231ddaSDan Williams dma_pool_free(isci_host->dma_pool, isci_request, 2486f231ddaSDan Williams isci_request->request_daddr); 2496f231ddaSDan Williams } 2506f231ddaSDan Williams 2516f231ddaSDan Williams 2526f231ddaSDan Williams /* #define ISCI_REQUEST_VALIDATE_ACCESS 2536f231ddaSDan Williams */ 2546f231ddaSDan Williams 2556f231ddaSDan Williams #ifdef ISCI_REQUEST_VALIDATE_ACCESS 2566f231ddaSDan Williams 2576f231ddaSDan Williams static inline 2586f231ddaSDan Williams struct sas_task *isci_request_access_task(struct isci_request *isci_request) 2596f231ddaSDan Williams { 2606f231ddaSDan Williams BUG_ON(isci_request->ttype != io_task); 2616f231ddaSDan Williams return isci_request->ttype_ptr.io_task_ptr; 2626f231ddaSDan Williams } 2636f231ddaSDan Williams 2646f231ddaSDan Williams static inline 2656f231ddaSDan Williams struct isci_tmf *isci_request_access_tmf(struct isci_request *isci_request) 2666f231ddaSDan Williams { 2676f231ddaSDan Williams BUG_ON(isci_request->ttype != tmf_task); 2686f231ddaSDan Williams return isci_request->ttype_ptr.tmf_task_ptr; 2696f231ddaSDan Williams } 2706f231ddaSDan Williams 2716f231ddaSDan Williams #else /* not ISCI_REQUEST_VALIDATE_ACCESS */ 2726f231ddaSDan Williams 2736f231ddaSDan Williams #define isci_request_access_task(RequestPtr) \ 2746f231ddaSDan Williams ((RequestPtr)->ttype_ptr.io_task_ptr) 2756f231ddaSDan Williams 2766f231ddaSDan Williams #define isci_request_access_tmf(RequestPtr) \ 2776f231ddaSDan Williams ((RequestPtr)->ttype_ptr.tmf_task_ptr) 2786f231ddaSDan Williams 2796f231ddaSDan Williams #endif /* not ISCI_REQUEST_VALIDATE_ACCESS */ 2806f231ddaSDan Williams 2816f231ddaSDan Williams 2826f231ddaSDan Williams int isci_request_alloc_tmf( 2836f231ddaSDan Williams struct isci_host *isci_host, 2846f231ddaSDan Williams struct isci_tmf *isci_tmf, 2856f231ddaSDan Williams struct isci_request **isci_request, 2866f231ddaSDan Williams struct isci_remote_device *isci_device, 2876f231ddaSDan Williams gfp_t gfp_flags); 2886f231ddaSDan Williams 2896f231ddaSDan Williams 2906f231ddaSDan Williams int isci_request_execute( 2916f231ddaSDan Williams struct isci_host *isci_host, 2926f231ddaSDan Williams struct sas_task *task, 2936f231ddaSDan Williams struct isci_request **request, 2946f231ddaSDan Williams gfp_t gfp_flags); 2956f231ddaSDan Williams 2966f231ddaSDan Williams /** 2976f231ddaSDan Williams * isci_request_unmap_sgl() - This function unmaps the DMA address of a given 2986f231ddaSDan Williams * sgl 2996f231ddaSDan Williams * @request: This parameter points to the isci_request object 3006f231ddaSDan Williams * @*pdev: This Parameter is the pci_device struct for the controller 3016f231ddaSDan Williams * 3026f231ddaSDan Williams */ 3036f231ddaSDan Williams static inline void isci_request_unmap_sgl( 3046f231ddaSDan Williams struct isci_request *request, 3056f231ddaSDan Williams struct pci_dev *pdev) 3066f231ddaSDan Williams { 3076f231ddaSDan Williams struct sas_task *task = isci_request_access_task(request); 3086f231ddaSDan Williams 3096f231ddaSDan Williams dev_dbg(&request->isci_host->pdev->dev, 3106f231ddaSDan Williams "%s: request = %p, task = %p,\n" 3116f231ddaSDan Williams "task->data_dir = %d, is_sata = %d\n ", 3126f231ddaSDan Williams __func__, 3136f231ddaSDan Williams request, 3146f231ddaSDan Williams task, 3156f231ddaSDan Williams task->data_dir, 3166f231ddaSDan Williams sas_protocol_ata(task->task_proto)); 3176f231ddaSDan Williams 3186f231ddaSDan Williams if ((task->data_dir != PCI_DMA_NONE) && 3196f231ddaSDan Williams !sas_protocol_ata(task->task_proto)) { 3206f231ddaSDan Williams if (task->num_scatter == 0) 3216f231ddaSDan Williams /* 0 indicates a single dma address */ 3226f231ddaSDan Williams dma_unmap_single( 3236f231ddaSDan Williams &pdev->dev, 3246f231ddaSDan Williams request->zero_scatter_daddr, 3256f231ddaSDan Williams task->total_xfer_len, 3266f231ddaSDan Williams task->data_dir 3276f231ddaSDan Williams ); 3286f231ddaSDan Williams 3296f231ddaSDan Williams else /* unmap the sgl dma addresses */ 3306f231ddaSDan Williams dma_unmap_sg( 3316f231ddaSDan Williams &pdev->dev, 3326f231ddaSDan Williams task->scatter, 3336f231ddaSDan Williams request->num_sg_entries, 3346f231ddaSDan Williams task->data_dir 3356f231ddaSDan Williams ); 3366f231ddaSDan Williams } 3376f231ddaSDan Williams } 3386f231ddaSDan Williams 3396f231ddaSDan Williams 3406f231ddaSDan Williams void isci_request_io_request_complete( 3416f231ddaSDan Williams struct isci_host *isci_host, 3426f231ddaSDan Williams struct isci_request *request, 3436f231ddaSDan Williams enum sci_io_status completion_status); 3446f231ddaSDan Williams 3456f231ddaSDan Williams /** 3466f231ddaSDan Williams * isci_request_io_request_get_next_sge() - This function is called by the sci 3476f231ddaSDan Williams * core to retrieve the next sge for a given request. 3486f231ddaSDan Williams * @request: This parameter is the isci_request object. 3496f231ddaSDan Williams * @current_sge_address: This parameter is the last sge retrieved by the sci 3506f231ddaSDan Williams * core for this request. 3516f231ddaSDan Williams * 3526f231ddaSDan Williams * pointer to the next sge for specified request. 3536f231ddaSDan Williams */ 3546f231ddaSDan Williams static inline void *isci_request_io_request_get_next_sge( 3556f231ddaSDan Williams struct isci_request *request, 3566f231ddaSDan Williams void *current_sge_address) 3576f231ddaSDan Williams { 3586f231ddaSDan Williams struct sas_task *task = isci_request_access_task(request); 3596f231ddaSDan Williams void *ret = NULL; 3606f231ddaSDan Williams 3616f231ddaSDan Williams dev_dbg(&request->isci_host->pdev->dev, 3626f231ddaSDan Williams "%s: request = %p, " 3636f231ddaSDan Williams "current_sge_address = %p, " 3646f231ddaSDan Williams "num_scatter = %d\n", 3656f231ddaSDan Williams __func__, 3666f231ddaSDan Williams request, 3676f231ddaSDan Williams current_sge_address, 3686f231ddaSDan Williams task->num_scatter); 3696f231ddaSDan Williams 3706f231ddaSDan Williams if (!current_sge_address) /* First time through.. */ 3716f231ddaSDan Williams ret = task->scatter; /* always task->scatter */ 3726f231ddaSDan Williams else if (task->num_scatter == 0) /* Next element, if num_scatter == 0 */ 3736f231ddaSDan Williams ret = NULL; /* there is only one element. */ 3746f231ddaSDan Williams else 3756f231ddaSDan Williams ret = sg_next(current_sge_address); /* sg_next returns NULL 3766f231ddaSDan Williams * for the last element 3776f231ddaSDan Williams */ 3786f231ddaSDan Williams 3796f231ddaSDan Williams dev_dbg(&request->isci_host->pdev->dev, 3806f231ddaSDan Williams "%s: next sge address = %p\n", 3816f231ddaSDan Williams __func__, 3826f231ddaSDan Williams ret); 3836f231ddaSDan Williams 3846f231ddaSDan Williams return ret; 3856f231ddaSDan Williams } 3866f231ddaSDan Williams 3876f231ddaSDan Williams 3886f231ddaSDan Williams void isci_terminate_pending_requests( 3896f231ddaSDan Williams struct isci_host *isci_host, 3906f231ddaSDan Williams struct isci_remote_device *isci_device, 3916f231ddaSDan Williams enum isci_request_status new_request_state); 3926f231ddaSDan Williams 3936f231ddaSDan Williams 3946f231ddaSDan Williams 3956f231ddaSDan Williams 3966f231ddaSDan Williams #endif /* !defined(_ISCI_REQUEST_H_) */ 397