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" 60*ce2b3261SDan Williams #include "host.h" 610d84366fSDan Williams #include "scic_sds_request.h" 626f231ddaSDan Williams 636f231ddaSDan Williams /** 646f231ddaSDan Williams * struct isci_request_status - This enum defines the possible states of an I/O 656f231ddaSDan Williams * request. 666f231ddaSDan Williams * 676f231ddaSDan Williams * 686f231ddaSDan Williams */ 696f231ddaSDan Williams enum isci_request_status { 706f231ddaSDan Williams unallocated = 0x00, 716f231ddaSDan Williams allocated = 0x01, 726f231ddaSDan Williams started = 0x02, 736f231ddaSDan Williams completed = 0x03, 746f231ddaSDan Williams aborting = 0x04, 756f231ddaSDan Williams aborted = 0x05, 764dc043c4SJeff Skirvin terminating = 0x06, 774dc043c4SJeff Skirvin dead = 0x07 786f231ddaSDan Williams }; 796f231ddaSDan Williams 806f231ddaSDan Williams enum task_type { 816f231ddaSDan Williams io_task = 0, 826f231ddaSDan Williams tmf_task = 1 836f231ddaSDan Williams }; 846f231ddaSDan Williams 856f231ddaSDan Williams struct isci_request { 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; 9067ea838dSDan Williams bool terminated; 916f231ddaSDan Williams 926f231ddaSDan Williams union ttype_ptr_union { 936f231ddaSDan Williams struct sas_task *io_task_ptr; /* When ttype==io_task */ 946f231ddaSDan Williams struct isci_tmf *tmf_task_ptr; /* When ttype==tmf_task */ 956f231ddaSDan Williams } ttype_ptr; 966f231ddaSDan Williams struct isci_host *isci_host; 976f231ddaSDan Williams struct isci_remote_device *isci_device; 986f231ddaSDan Williams /* For use in the requests_to_{complete|abort} lists: */ 996f231ddaSDan Williams struct list_head completed_node; 1006f231ddaSDan Williams /* For use in the reqs_in_process list: */ 1016f231ddaSDan Williams struct list_head dev_node; 1026f231ddaSDan Williams spinlock_t state_lock; 1036f231ddaSDan Williams dma_addr_t request_daddr; 1046f231ddaSDan Williams dma_addr_t zero_scatter_daddr; 1056f231ddaSDan Williams 1066f231ddaSDan Williams unsigned int num_sg_entries; /* returned by pci_alloc_sg */ 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; 11867ea838dSDan Williams struct scic_sds_request sci; 1196f231ddaSDan Williams }; 1206f231ddaSDan Williams 12167ea838dSDan Williams static inline struct isci_request *sci_req_to_ireq(struct scic_sds_request *sci_req) 12267ea838dSDan Williams { 12367ea838dSDan Williams struct isci_request *ireq = container_of(sci_req, typeof(*ireq), sci); 12467ea838dSDan Williams 12567ea838dSDan Williams return ireq; 12667ea838dSDan Williams } 12767ea838dSDan Williams 1286f231ddaSDan Williams /** 1296f231ddaSDan Williams * This function gets the status of the request object. 1306f231ddaSDan Williams * @request: This parameter points to the isci_request object 1316f231ddaSDan Williams * 1326f231ddaSDan Williams * status of the object as a isci_request_status enum. 1336f231ddaSDan Williams */ 1346f231ddaSDan Williams static inline 1356f231ddaSDan Williams enum isci_request_status isci_request_get_state( 1366f231ddaSDan Williams struct isci_request *isci_request) 1376f231ddaSDan Williams { 1386f231ddaSDan Williams BUG_ON(isci_request == NULL); 1396f231ddaSDan Williams 1406f231ddaSDan Williams /*probably a bad sign... */ 1416f231ddaSDan Williams if (isci_request->status == unallocated) 1426f231ddaSDan Williams dev_warn(&isci_request->isci_host->pdev->dev, 1436f231ddaSDan Williams "%s: isci_request->status == unallocated\n", 1446f231ddaSDan Williams __func__); 1456f231ddaSDan Williams 1466f231ddaSDan Williams return isci_request->status; 1476f231ddaSDan Williams } 1486f231ddaSDan Williams 1496f231ddaSDan Williams 1506f231ddaSDan Williams /** 1516f231ddaSDan Williams * isci_request_change_state() - This function sets the status of the request 1526f231ddaSDan Williams * object. 1536f231ddaSDan Williams * @request: This parameter points to the isci_request object 1546f231ddaSDan Williams * @status: This Parameter is the new status of the object 1556f231ddaSDan Williams * 1566f231ddaSDan Williams */ 1576f231ddaSDan Williams static inline enum isci_request_status isci_request_change_state( 1586f231ddaSDan Williams struct isci_request *isci_request, 1596f231ddaSDan Williams enum isci_request_status status) 1606f231ddaSDan Williams { 1616f231ddaSDan Williams enum isci_request_status old_state; 1626f231ddaSDan Williams unsigned long flags; 1636f231ddaSDan Williams 1646f231ddaSDan Williams dev_dbg(&isci_request->isci_host->pdev->dev, 1656f231ddaSDan Williams "%s: isci_request = %p, state = 0x%x\n", 1666f231ddaSDan Williams __func__, 1676f231ddaSDan Williams isci_request, 1686f231ddaSDan Williams status); 1696f231ddaSDan Williams 1706f231ddaSDan Williams BUG_ON(isci_request == NULL); 1716f231ddaSDan Williams 1726f231ddaSDan Williams spin_lock_irqsave(&isci_request->state_lock, flags); 1736f231ddaSDan Williams old_state = isci_request->status; 1746f231ddaSDan Williams isci_request->status = status; 1756f231ddaSDan Williams spin_unlock_irqrestore(&isci_request->state_lock, flags); 1766f231ddaSDan Williams 1776f231ddaSDan Williams return old_state; 1786f231ddaSDan Williams } 1796f231ddaSDan Williams 1806f231ddaSDan Williams /** 1816f231ddaSDan Williams * isci_request_change_started_to_newstate() - This function sets the status of 1826f231ddaSDan Williams * the request object. 1836f231ddaSDan Williams * @request: This parameter points to the isci_request object 1846f231ddaSDan Williams * @status: This Parameter is the new status of the object 1856f231ddaSDan Williams * 1866f231ddaSDan Williams * state previous to any change. 1876f231ddaSDan Williams */ 1886f231ddaSDan Williams static inline enum isci_request_status isci_request_change_started_to_newstate( 1896f231ddaSDan Williams struct isci_request *isci_request, 1906f231ddaSDan Williams struct completion *completion_ptr, 1916f231ddaSDan Williams enum isci_request_status newstate) 1926f231ddaSDan Williams { 1936f231ddaSDan Williams enum isci_request_status old_state; 1946f231ddaSDan Williams unsigned long flags; 1956f231ddaSDan Williams 1966f231ddaSDan Williams spin_lock_irqsave(&isci_request->state_lock, flags); 1976f231ddaSDan Williams 1986f231ddaSDan Williams old_state = isci_request->status; 1996f231ddaSDan Williams 200f219f010SJeff Skirvin if (old_state == started || old_state == aborting) { 2016f231ddaSDan Williams BUG_ON(isci_request->io_request_completion != NULL); 2026f231ddaSDan Williams 2036f231ddaSDan Williams isci_request->io_request_completion = completion_ptr; 2046f231ddaSDan Williams isci_request->status = newstate; 2056f231ddaSDan Williams } 2066f231ddaSDan Williams spin_unlock_irqrestore(&isci_request->state_lock, flags); 2076f231ddaSDan Williams 2086f231ddaSDan Williams dev_dbg(&isci_request->isci_host->pdev->dev, 2096f231ddaSDan Williams "%s: isci_request = %p, old_state = 0x%x\n", 2106f231ddaSDan Williams __func__, 2116f231ddaSDan Williams isci_request, 2126f231ddaSDan Williams old_state); 2136f231ddaSDan Williams 2146f231ddaSDan Williams return old_state; 2156f231ddaSDan Williams } 2166f231ddaSDan Williams 2176f231ddaSDan Williams /** 2186f231ddaSDan Williams * isci_request_change_started_to_aborted() - This function sets the status of 2196f231ddaSDan Williams * the request object. 2206f231ddaSDan Williams * @request: This parameter points to the isci_request object 2216f231ddaSDan Williams * @completion_ptr: This parameter is saved as the kernel completion structure 2226f231ddaSDan Williams * signalled when the old request completes. 2236f231ddaSDan Williams * 2246f231ddaSDan Williams * state previous to any change. 2256f231ddaSDan Williams */ 2266f231ddaSDan Williams static inline enum isci_request_status isci_request_change_started_to_aborted( 2276f231ddaSDan Williams struct isci_request *isci_request, 2286f231ddaSDan Williams struct completion *completion_ptr) 2296f231ddaSDan Williams { 2306f231ddaSDan Williams return isci_request_change_started_to_newstate( 2316f231ddaSDan Williams isci_request, completion_ptr, aborted 2326f231ddaSDan Williams ); 2336f231ddaSDan Williams } 2346f231ddaSDan Williams /** 2356f231ddaSDan Williams * isci_request_free() - This function frees the request object. 2366f231ddaSDan Williams * @isci_host: This parameter specifies the ISCI host object 2376f231ddaSDan Williams * @isci_request: This parameter points to the isci_request object 2386f231ddaSDan Williams * 2396f231ddaSDan Williams */ 2406f231ddaSDan Williams static inline void isci_request_free( 2416f231ddaSDan Williams struct isci_host *isci_host, 2426f231ddaSDan Williams struct isci_request *isci_request) 2436f231ddaSDan Williams { 2446cb4d6b3SBartosz Barcinski if (!isci_request) 2456cb4d6b3SBartosz Barcinski return; 2466f231ddaSDan Williams 2476f231ddaSDan Williams /* release the dma memory if we fail. */ 2486f231ddaSDan Williams dma_pool_free(isci_host->dma_pool, isci_request, 2496f231ddaSDan Williams isci_request->request_daddr); 2506f231ddaSDan Williams } 2516f231ddaSDan Williams 2526f231ddaSDan Williams 2536f231ddaSDan Williams /* #define ISCI_REQUEST_VALIDATE_ACCESS 2546f231ddaSDan Williams */ 2556f231ddaSDan Williams 2566f231ddaSDan Williams #ifdef ISCI_REQUEST_VALIDATE_ACCESS 2576f231ddaSDan Williams 2586f231ddaSDan Williams static inline 2596f231ddaSDan Williams struct sas_task *isci_request_access_task(struct isci_request *isci_request) 2606f231ddaSDan Williams { 2616f231ddaSDan Williams BUG_ON(isci_request->ttype != io_task); 2626f231ddaSDan Williams return isci_request->ttype_ptr.io_task_ptr; 2636f231ddaSDan Williams } 2646f231ddaSDan Williams 2656f231ddaSDan Williams static inline 2666f231ddaSDan Williams struct isci_tmf *isci_request_access_tmf(struct isci_request *isci_request) 2676f231ddaSDan Williams { 2686f231ddaSDan Williams BUG_ON(isci_request->ttype != tmf_task); 2696f231ddaSDan Williams return isci_request->ttype_ptr.tmf_task_ptr; 2706f231ddaSDan Williams } 2716f231ddaSDan Williams 2726f231ddaSDan Williams #else /* not ISCI_REQUEST_VALIDATE_ACCESS */ 2736f231ddaSDan Williams 2746f231ddaSDan Williams #define isci_request_access_task(RequestPtr) \ 2756f231ddaSDan Williams ((RequestPtr)->ttype_ptr.io_task_ptr) 2766f231ddaSDan Williams 2776f231ddaSDan Williams #define isci_request_access_tmf(RequestPtr) \ 2786f231ddaSDan Williams ((RequestPtr)->ttype_ptr.tmf_task_ptr) 2796f231ddaSDan Williams 2806f231ddaSDan Williams #endif /* not ISCI_REQUEST_VALIDATE_ACCESS */ 2816f231ddaSDan Williams 2826f231ddaSDan Williams 2836f231ddaSDan Williams int isci_request_alloc_tmf( 2846f231ddaSDan Williams struct isci_host *isci_host, 2856f231ddaSDan Williams struct isci_tmf *isci_tmf, 2866f231ddaSDan Williams struct isci_request **isci_request, 2876f231ddaSDan Williams struct isci_remote_device *isci_device, 2886f231ddaSDan Williams gfp_t gfp_flags); 2896f231ddaSDan Williams 2906f231ddaSDan Williams 2916f231ddaSDan Williams int isci_request_execute( 2926f231ddaSDan Williams struct isci_host *isci_host, 2936f231ddaSDan Williams struct sas_task *task, 2946f231ddaSDan Williams struct isci_request **request, 2956f231ddaSDan Williams gfp_t gfp_flags); 2966f231ddaSDan Williams 2976f231ddaSDan Williams /** 2986f231ddaSDan Williams * isci_request_unmap_sgl() - This function unmaps the DMA address of a given 2996f231ddaSDan Williams * sgl 3006f231ddaSDan Williams * @request: This parameter points to the isci_request object 3016f231ddaSDan Williams * @*pdev: This Parameter is the pci_device struct for the controller 3026f231ddaSDan Williams * 3036f231ddaSDan Williams */ 3046f231ddaSDan Williams static inline void isci_request_unmap_sgl( 3056f231ddaSDan Williams struct isci_request *request, 3066f231ddaSDan Williams struct pci_dev *pdev) 3076f231ddaSDan Williams { 3086f231ddaSDan Williams struct sas_task *task = isci_request_access_task(request); 3096f231ddaSDan Williams 3106f231ddaSDan Williams dev_dbg(&request->isci_host->pdev->dev, 3116f231ddaSDan Williams "%s: request = %p, task = %p,\n" 3126f231ddaSDan Williams "task->data_dir = %d, is_sata = %d\n ", 3136f231ddaSDan Williams __func__, 3146f231ddaSDan Williams request, 3156f231ddaSDan Williams task, 3166f231ddaSDan Williams task->data_dir, 3176f231ddaSDan Williams sas_protocol_ata(task->task_proto)); 3186f231ddaSDan Williams 3196f231ddaSDan Williams if ((task->data_dir != PCI_DMA_NONE) && 3206f231ddaSDan Williams !sas_protocol_ata(task->task_proto)) { 3216f231ddaSDan Williams if (task->num_scatter == 0) 3226f231ddaSDan Williams /* 0 indicates a single dma address */ 3236f231ddaSDan Williams dma_unmap_single( 3246f231ddaSDan Williams &pdev->dev, 3256f231ddaSDan Williams request->zero_scatter_daddr, 3266f231ddaSDan Williams task->total_xfer_len, 3276f231ddaSDan Williams task->data_dir 3286f231ddaSDan Williams ); 3296f231ddaSDan Williams 3306f231ddaSDan Williams else /* unmap the sgl dma addresses */ 3316f231ddaSDan Williams dma_unmap_sg( 3326f231ddaSDan Williams &pdev->dev, 3336f231ddaSDan Williams task->scatter, 3346f231ddaSDan Williams request->num_sg_entries, 3356f231ddaSDan Williams task->data_dir 3366f231ddaSDan Williams ); 3376f231ddaSDan Williams } 3386f231ddaSDan Williams } 3396f231ddaSDan Williams 3406f231ddaSDan Williams 3416f231ddaSDan Williams void isci_request_io_request_complete( 3426f231ddaSDan Williams struct isci_host *isci_host, 3436f231ddaSDan Williams struct isci_request *request, 3446f231ddaSDan Williams enum sci_io_status completion_status); 3456f231ddaSDan Williams 3466f231ddaSDan Williams /** 3476f231ddaSDan Williams * isci_request_io_request_get_next_sge() - This function is called by the sci 3486f231ddaSDan Williams * core to retrieve the next sge for a given request. 3496f231ddaSDan Williams * @request: This parameter is the isci_request object. 3506f231ddaSDan Williams * @current_sge_address: This parameter is the last sge retrieved by the sci 3516f231ddaSDan Williams * core for this request. 3526f231ddaSDan Williams * 3536f231ddaSDan Williams * pointer to the next sge for specified request. 3546f231ddaSDan Williams */ 3556f231ddaSDan Williams static inline void *isci_request_io_request_get_next_sge( 3566f231ddaSDan Williams struct isci_request *request, 3576f231ddaSDan Williams void *current_sge_address) 3586f231ddaSDan Williams { 3596f231ddaSDan Williams struct sas_task *task = isci_request_access_task(request); 3606f231ddaSDan Williams void *ret = NULL; 3616f231ddaSDan Williams 3626f231ddaSDan Williams dev_dbg(&request->isci_host->pdev->dev, 3636f231ddaSDan Williams "%s: request = %p, " 3646f231ddaSDan Williams "current_sge_address = %p, " 3656f231ddaSDan Williams "num_scatter = %d\n", 3666f231ddaSDan Williams __func__, 3676f231ddaSDan Williams request, 3686f231ddaSDan Williams current_sge_address, 3696f231ddaSDan Williams task->num_scatter); 3706f231ddaSDan Williams 3716f231ddaSDan Williams if (!current_sge_address) /* First time through.. */ 3726f231ddaSDan Williams ret = task->scatter; /* always task->scatter */ 3736f231ddaSDan Williams else if (task->num_scatter == 0) /* Next element, if num_scatter == 0 */ 3746f231ddaSDan Williams ret = NULL; /* there is only one element. */ 3756f231ddaSDan Williams else 3766f231ddaSDan Williams ret = sg_next(current_sge_address); /* sg_next returns NULL 3776f231ddaSDan Williams * for the last element 3786f231ddaSDan Williams */ 3796f231ddaSDan Williams 3806f231ddaSDan Williams dev_dbg(&request->isci_host->pdev->dev, 3816f231ddaSDan Williams "%s: next sge address = %p\n", 3826f231ddaSDan Williams __func__, 3836f231ddaSDan Williams ret); 3846f231ddaSDan Williams 3856f231ddaSDan Williams return ret; 3866f231ddaSDan Williams } 3876f231ddaSDan Williams 3886f231ddaSDan Williams 3896f231ddaSDan Williams void isci_terminate_pending_requests( 3906f231ddaSDan Williams struct isci_host *isci_host, 3916f231ddaSDan Williams struct isci_remote_device *isci_device, 3926f231ddaSDan Williams enum isci_request_status new_request_state); 3936f231ddaSDan Williams 3946f231ddaSDan Williams 3956f231ddaSDan Williams 3966f231ddaSDan Williams 3976f231ddaSDan Williams #endif /* !defined(_ISCI_REQUEST_H_) */ 398