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 56*0d84366fSDan Williams #ifndef _ISCI_REQUEST_H_ 576f231ddaSDan Williams #define _ISCI_REQUEST_H_ 586f231ddaSDan Williams 596f231ddaSDan Williams #include "isci.h" 60*0d84366fSDan 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 struct scic_sds_request *sci_request_handle; 866f231ddaSDan Williams enum isci_request_status status; 876f231ddaSDan Williams enum task_type ttype; 886f231ddaSDan Williams unsigned short io_tag; 896f231ddaSDan Williams bool complete_in_target; 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 unsigned int request_alloc_size; /* size of block from dma_pool_alloc */ 1076f231ddaSDan Williams 1086f231ddaSDan Williams /** Note: "io_request_completion" is completed in two different ways 1096f231ddaSDan Williams * depending on whether this is a TMF or regular request. 1106f231ddaSDan Williams * - TMF requests are completed in the thread that started them; 1116f231ddaSDan Williams * - regular requests are completed in the request completion callback 1126f231ddaSDan Williams * function. 1136f231ddaSDan Williams * This difference in operation allows the aborter of a TMF request 1146f231ddaSDan Williams * to be sure that once the TMF request completes, the I/O that the 1156f231ddaSDan Williams * TMF was aborting is guaranteed to have completed. 1166f231ddaSDan Williams */ 1176f231ddaSDan Williams struct completion *io_request_completion; 118*0d84366fSDan Williams struct scic_sds_request sci_req[0] ____cacheline_aligned; 1196f231ddaSDan Williams }; 1206f231ddaSDan Williams 1216f231ddaSDan Williams /** 1226f231ddaSDan Williams * This function gets the status of the request object. 1236f231ddaSDan Williams * @request: This parameter points to the isci_request object 1246f231ddaSDan Williams * 1256f231ddaSDan Williams * status of the object as a isci_request_status enum. 1266f231ddaSDan Williams */ 1276f231ddaSDan Williams static inline 1286f231ddaSDan Williams enum isci_request_status isci_request_get_state( 1296f231ddaSDan Williams struct isci_request *isci_request) 1306f231ddaSDan Williams { 1316f231ddaSDan Williams BUG_ON(isci_request == NULL); 1326f231ddaSDan Williams 1336f231ddaSDan Williams /*probably a bad sign... */ 1346f231ddaSDan Williams if (isci_request->status == unallocated) 1356f231ddaSDan Williams dev_warn(&isci_request->isci_host->pdev->dev, 1366f231ddaSDan Williams "%s: isci_request->status == unallocated\n", 1376f231ddaSDan Williams __func__); 1386f231ddaSDan Williams 1396f231ddaSDan Williams return isci_request->status; 1406f231ddaSDan Williams } 1416f231ddaSDan Williams 1426f231ddaSDan Williams 1436f231ddaSDan Williams /** 1446f231ddaSDan Williams * isci_request_change_state() - This function sets the status of the request 1456f231ddaSDan Williams * object. 1466f231ddaSDan Williams * @request: This parameter points to the isci_request object 1476f231ddaSDan Williams * @status: This Parameter is the new status of the object 1486f231ddaSDan Williams * 1496f231ddaSDan Williams */ 1506f231ddaSDan Williams static inline enum isci_request_status isci_request_change_state( 1516f231ddaSDan Williams struct isci_request *isci_request, 1526f231ddaSDan Williams enum isci_request_status status) 1536f231ddaSDan Williams { 1546f231ddaSDan Williams enum isci_request_status old_state; 1556f231ddaSDan Williams unsigned long flags; 1566f231ddaSDan Williams 1576f231ddaSDan Williams dev_dbg(&isci_request->isci_host->pdev->dev, 1586f231ddaSDan Williams "%s: isci_request = %p, state = 0x%x\n", 1596f231ddaSDan Williams __func__, 1606f231ddaSDan Williams isci_request, 1616f231ddaSDan Williams status); 1626f231ddaSDan Williams 1636f231ddaSDan Williams BUG_ON(isci_request == NULL); 1646f231ddaSDan Williams 1656f231ddaSDan Williams spin_lock_irqsave(&isci_request->state_lock, flags); 1666f231ddaSDan Williams old_state = isci_request->status; 1676f231ddaSDan Williams isci_request->status = status; 1686f231ddaSDan Williams spin_unlock_irqrestore(&isci_request->state_lock, flags); 1696f231ddaSDan Williams 1706f231ddaSDan Williams return old_state; 1716f231ddaSDan Williams } 1726f231ddaSDan Williams 1736f231ddaSDan Williams /** 1746f231ddaSDan Williams * isci_request_change_started_to_newstate() - This function sets the status of 1756f231ddaSDan Williams * the request object. 1766f231ddaSDan Williams * @request: This parameter points to the isci_request object 1776f231ddaSDan Williams * @status: This Parameter is the new status of the object 1786f231ddaSDan Williams * 1796f231ddaSDan Williams * state previous to any change. 1806f231ddaSDan Williams */ 1816f231ddaSDan Williams static inline enum isci_request_status isci_request_change_started_to_newstate( 1826f231ddaSDan Williams struct isci_request *isci_request, 1836f231ddaSDan Williams struct completion *completion_ptr, 1846f231ddaSDan Williams enum isci_request_status newstate) 1856f231ddaSDan Williams { 1866f231ddaSDan Williams enum isci_request_status old_state; 1876f231ddaSDan Williams unsigned long flags; 1886f231ddaSDan Williams 1896f231ddaSDan Williams spin_lock_irqsave(&isci_request->state_lock, flags); 1906f231ddaSDan Williams 1916f231ddaSDan Williams old_state = isci_request->status; 1926f231ddaSDan Williams 193f219f010SJeff Skirvin if (old_state == started || old_state == aborting) { 1946f231ddaSDan Williams BUG_ON(isci_request->io_request_completion != NULL); 1956f231ddaSDan Williams 1966f231ddaSDan Williams isci_request->io_request_completion = completion_ptr; 1976f231ddaSDan Williams isci_request->status = newstate; 1986f231ddaSDan Williams } 1996f231ddaSDan Williams spin_unlock_irqrestore(&isci_request->state_lock, flags); 2006f231ddaSDan Williams 2016f231ddaSDan Williams dev_dbg(&isci_request->isci_host->pdev->dev, 2026f231ddaSDan Williams "%s: isci_request = %p, old_state = 0x%x\n", 2036f231ddaSDan Williams __func__, 2046f231ddaSDan Williams isci_request, 2056f231ddaSDan Williams old_state); 2066f231ddaSDan Williams 2076f231ddaSDan Williams return old_state; 2086f231ddaSDan Williams } 2096f231ddaSDan Williams 2106f231ddaSDan Williams /** 2116f231ddaSDan Williams * isci_request_change_started_to_aborted() - This function sets the status of 2126f231ddaSDan Williams * the request object. 2136f231ddaSDan Williams * @request: This parameter points to the isci_request object 2146f231ddaSDan Williams * @completion_ptr: This parameter is saved as the kernel completion structure 2156f231ddaSDan Williams * signalled when the old request completes. 2166f231ddaSDan Williams * 2176f231ddaSDan Williams * state previous to any change. 2186f231ddaSDan Williams */ 2196f231ddaSDan Williams static inline enum isci_request_status isci_request_change_started_to_aborted( 2206f231ddaSDan Williams struct isci_request *isci_request, 2216f231ddaSDan Williams struct completion *completion_ptr) 2226f231ddaSDan Williams { 2236f231ddaSDan Williams return isci_request_change_started_to_newstate( 2246f231ddaSDan Williams isci_request, completion_ptr, aborted 2256f231ddaSDan Williams ); 2266f231ddaSDan Williams } 2276f231ddaSDan Williams /** 2286f231ddaSDan Williams * isci_request_free() - This function frees the request object. 2296f231ddaSDan Williams * @isci_host: This parameter specifies the ISCI host object 2306f231ddaSDan Williams * @isci_request: This parameter points to the isci_request object 2316f231ddaSDan Williams * 2326f231ddaSDan Williams */ 2336f231ddaSDan Williams static inline void isci_request_free( 2346f231ddaSDan Williams struct isci_host *isci_host, 2356f231ddaSDan Williams struct isci_request *isci_request) 2366f231ddaSDan Williams { 2376cb4d6b3SBartosz Barcinski if (!isci_request) 2386cb4d6b3SBartosz Barcinski return; 2396f231ddaSDan Williams 2406f231ddaSDan Williams /* release the dma memory if we fail. */ 2416f231ddaSDan Williams dma_pool_free(isci_host->dma_pool, isci_request, 2426f231ddaSDan Williams isci_request->request_daddr); 2436f231ddaSDan Williams } 2446f231ddaSDan Williams 2456f231ddaSDan Williams 2466f231ddaSDan Williams /* #define ISCI_REQUEST_VALIDATE_ACCESS 2476f231ddaSDan Williams */ 2486f231ddaSDan Williams 2496f231ddaSDan Williams #ifdef ISCI_REQUEST_VALIDATE_ACCESS 2506f231ddaSDan Williams 2516f231ddaSDan Williams static inline 2526f231ddaSDan Williams struct sas_task *isci_request_access_task(struct isci_request *isci_request) 2536f231ddaSDan Williams { 2546f231ddaSDan Williams BUG_ON(isci_request->ttype != io_task); 2556f231ddaSDan Williams return isci_request->ttype_ptr.io_task_ptr; 2566f231ddaSDan Williams } 2576f231ddaSDan Williams 2586f231ddaSDan Williams static inline 2596f231ddaSDan Williams struct isci_tmf *isci_request_access_tmf(struct isci_request *isci_request) 2606f231ddaSDan Williams { 2616f231ddaSDan Williams BUG_ON(isci_request->ttype != tmf_task); 2626f231ddaSDan Williams return isci_request->ttype_ptr.tmf_task_ptr; 2636f231ddaSDan Williams } 2646f231ddaSDan Williams 2656f231ddaSDan Williams #else /* not ISCI_REQUEST_VALIDATE_ACCESS */ 2666f231ddaSDan Williams 2676f231ddaSDan Williams #define isci_request_access_task(RequestPtr) \ 2686f231ddaSDan Williams ((RequestPtr)->ttype_ptr.io_task_ptr) 2696f231ddaSDan Williams 2706f231ddaSDan Williams #define isci_request_access_tmf(RequestPtr) \ 2716f231ddaSDan Williams ((RequestPtr)->ttype_ptr.tmf_task_ptr) 2726f231ddaSDan Williams 2736f231ddaSDan Williams #endif /* not ISCI_REQUEST_VALIDATE_ACCESS */ 2746f231ddaSDan Williams 2756f231ddaSDan Williams 2766f231ddaSDan Williams int isci_request_alloc_tmf( 2776f231ddaSDan Williams struct isci_host *isci_host, 2786f231ddaSDan Williams struct isci_tmf *isci_tmf, 2796f231ddaSDan Williams struct isci_request **isci_request, 2806f231ddaSDan Williams struct isci_remote_device *isci_device, 2816f231ddaSDan Williams gfp_t gfp_flags); 2826f231ddaSDan Williams 2836f231ddaSDan Williams 2846f231ddaSDan Williams int isci_request_execute( 2856f231ddaSDan Williams struct isci_host *isci_host, 2866f231ddaSDan Williams struct sas_task *task, 2876f231ddaSDan Williams struct isci_request **request, 2886f231ddaSDan Williams gfp_t gfp_flags); 2896f231ddaSDan Williams 2906f231ddaSDan Williams /** 2916f231ddaSDan Williams * isci_request_unmap_sgl() - This function unmaps the DMA address of a given 2926f231ddaSDan Williams * sgl 2936f231ddaSDan Williams * @request: This parameter points to the isci_request object 2946f231ddaSDan Williams * @*pdev: This Parameter is the pci_device struct for the controller 2956f231ddaSDan Williams * 2966f231ddaSDan Williams */ 2976f231ddaSDan Williams static inline void isci_request_unmap_sgl( 2986f231ddaSDan Williams struct isci_request *request, 2996f231ddaSDan Williams struct pci_dev *pdev) 3006f231ddaSDan Williams { 3016f231ddaSDan Williams struct sas_task *task = isci_request_access_task(request); 3026f231ddaSDan Williams 3036f231ddaSDan Williams dev_dbg(&request->isci_host->pdev->dev, 3046f231ddaSDan Williams "%s: request = %p, task = %p,\n" 3056f231ddaSDan Williams "task->data_dir = %d, is_sata = %d\n ", 3066f231ddaSDan Williams __func__, 3076f231ddaSDan Williams request, 3086f231ddaSDan Williams task, 3096f231ddaSDan Williams task->data_dir, 3106f231ddaSDan Williams sas_protocol_ata(task->task_proto)); 3116f231ddaSDan Williams 3126f231ddaSDan Williams if ((task->data_dir != PCI_DMA_NONE) && 3136f231ddaSDan Williams !sas_protocol_ata(task->task_proto)) { 3146f231ddaSDan Williams if (task->num_scatter == 0) 3156f231ddaSDan Williams /* 0 indicates a single dma address */ 3166f231ddaSDan Williams dma_unmap_single( 3176f231ddaSDan Williams &pdev->dev, 3186f231ddaSDan Williams request->zero_scatter_daddr, 3196f231ddaSDan Williams task->total_xfer_len, 3206f231ddaSDan Williams task->data_dir 3216f231ddaSDan Williams ); 3226f231ddaSDan Williams 3236f231ddaSDan Williams else /* unmap the sgl dma addresses */ 3246f231ddaSDan Williams dma_unmap_sg( 3256f231ddaSDan Williams &pdev->dev, 3266f231ddaSDan Williams task->scatter, 3276f231ddaSDan Williams request->num_sg_entries, 3286f231ddaSDan Williams task->data_dir 3296f231ddaSDan Williams ); 3306f231ddaSDan Williams } 3316f231ddaSDan Williams } 3326f231ddaSDan Williams 3336f231ddaSDan Williams 3346f231ddaSDan Williams void isci_request_io_request_complete( 3356f231ddaSDan Williams struct isci_host *isci_host, 3366f231ddaSDan Williams struct isci_request *request, 3376f231ddaSDan Williams enum sci_io_status completion_status); 3386f231ddaSDan Williams 3396f231ddaSDan Williams /** 3406f231ddaSDan Williams * isci_request_io_request_get_next_sge() - This function is called by the sci 3416f231ddaSDan Williams * core to retrieve the next sge for a given request. 3426f231ddaSDan Williams * @request: This parameter is the isci_request object. 3436f231ddaSDan Williams * @current_sge_address: This parameter is the last sge retrieved by the sci 3446f231ddaSDan Williams * core for this request. 3456f231ddaSDan Williams * 3466f231ddaSDan Williams * pointer to the next sge for specified request. 3476f231ddaSDan Williams */ 3486f231ddaSDan Williams static inline void *isci_request_io_request_get_next_sge( 3496f231ddaSDan Williams struct isci_request *request, 3506f231ddaSDan Williams void *current_sge_address) 3516f231ddaSDan Williams { 3526f231ddaSDan Williams struct sas_task *task = isci_request_access_task(request); 3536f231ddaSDan Williams void *ret = NULL; 3546f231ddaSDan Williams 3556f231ddaSDan Williams dev_dbg(&request->isci_host->pdev->dev, 3566f231ddaSDan Williams "%s: request = %p, " 3576f231ddaSDan Williams "current_sge_address = %p, " 3586f231ddaSDan Williams "num_scatter = %d\n", 3596f231ddaSDan Williams __func__, 3606f231ddaSDan Williams request, 3616f231ddaSDan Williams current_sge_address, 3626f231ddaSDan Williams task->num_scatter); 3636f231ddaSDan Williams 3646f231ddaSDan Williams if (!current_sge_address) /* First time through.. */ 3656f231ddaSDan Williams ret = task->scatter; /* always task->scatter */ 3666f231ddaSDan Williams else if (task->num_scatter == 0) /* Next element, if num_scatter == 0 */ 3676f231ddaSDan Williams ret = NULL; /* there is only one element. */ 3686f231ddaSDan Williams else 3696f231ddaSDan Williams ret = sg_next(current_sge_address); /* sg_next returns NULL 3706f231ddaSDan Williams * for the last element 3716f231ddaSDan Williams */ 3726f231ddaSDan Williams 3736f231ddaSDan Williams dev_dbg(&request->isci_host->pdev->dev, 3746f231ddaSDan Williams "%s: next sge address = %p\n", 3756f231ddaSDan Williams __func__, 3766f231ddaSDan Williams ret); 3776f231ddaSDan Williams 3786f231ddaSDan Williams return ret; 3796f231ddaSDan Williams } 3806f231ddaSDan Williams 3816f231ddaSDan Williams 3826f231ddaSDan Williams void isci_terminate_pending_requests( 3836f231ddaSDan Williams struct isci_host *isci_host, 3846f231ddaSDan Williams struct isci_remote_device *isci_device, 3856f231ddaSDan Williams enum isci_request_status new_request_state); 3866f231ddaSDan Williams 3876f231ddaSDan Williams 3886f231ddaSDan Williams 3896f231ddaSDan Williams 3906f231ddaSDan Williams #endif /* !defined(_ISCI_REQUEST_H_) */ 391