Commit | Line | Data |
---|---|---|
6f231dda DW |
1 | /* |
2 | * This file is provided under a dual BSD/GPLv2 license. When using or | |
3 | * redistributing this file, you may do so under either license. | |
4 | * | |
5 | * GPL LICENSE SUMMARY | |
6 | * | |
7 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of version 2 of the GNU General Public License as | |
11 | * published by the Free Software Foundation. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | * The full GNU General Public License is included in this distribution | |
22 | * in the file called LICENSE.GPL. | |
23 | * | |
24 | * BSD LICENSE | |
25 | * | |
26 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | |
27 | * All rights reserved. | |
28 | * | |
29 | * Redistribution and use in source and binary forms, with or without | |
30 | * modification, are permitted provided that the following conditions | |
31 | * are met: | |
32 | * | |
33 | * * Redistributions of source code must retain the above copyright | |
34 | * notice, this list of conditions and the following disclaimer. | |
35 | * * Redistributions in binary form must reproduce the above copyright | |
36 | * notice, this list of conditions and the following disclaimer in | |
37 | * the documentation and/or other materials provided with the | |
38 | * distribution. | |
39 | * * Neither the name of Intel Corporation nor the names of its | |
40 | * contributors may be used to endorse or promote products derived | |
41 | * from this software without specific prior written permission. | |
42 | * | |
43 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
44 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
45 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
46 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
47 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
48 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
49 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
53 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
54 | */ | |
55 | ||
56 | #if !defined(_ISCI_REQUEST_H_) | |
57 | #define _ISCI_REQUEST_H_ | |
58 | ||
59 | #include "isci.h" | |
60 | ||
61 | /** | |
62 | * struct isci_request_status - This enum defines the possible states of an I/O | |
63 | * request. | |
64 | * | |
65 | * | |
66 | */ | |
67 | enum isci_request_status { | |
68 | unallocated = 0x00, | |
69 | allocated = 0x01, | |
70 | started = 0x02, | |
71 | completed = 0x03, | |
72 | aborting = 0x04, | |
73 | aborted = 0x05, | |
74 | terminating = 0x06 | |
75 | }; | |
76 | ||
77 | enum task_type { | |
78 | io_task = 0, | |
79 | tmf_task = 1 | |
80 | }; | |
81 | ||
82 | /** | |
83 | * struct isci_request - This class represents the request object used to track | |
84 | * IO, smp and TMF request internal. It wraps the SCIC request object. | |
85 | * | |
86 | * | |
87 | */ | |
88 | struct isci_request { | |
89 | ||
90 | struct scic_sds_request *sci_request_handle; | |
91 | ||
92 | enum isci_request_status status; | |
93 | enum task_type ttype; | |
94 | unsigned short io_tag; | |
95 | bool complete_in_target; | |
96 | ||
97 | union ttype_ptr_union { | |
98 | struct sas_task *io_task_ptr; /* When ttype==io_task */ | |
99 | struct isci_tmf *tmf_task_ptr; /* When ttype==tmf_task */ | |
100 | } ttype_ptr; | |
101 | struct isci_host *isci_host; | |
102 | struct isci_remote_device *isci_device; | |
103 | /* For use in the requests_to_{complete|abort} lists: */ | |
104 | struct list_head completed_node; | |
105 | /* For use in the reqs_in_process list: */ | |
106 | struct list_head dev_node; | |
107 | void *sci_request_mem_ptr; | |
108 | spinlock_t state_lock; | |
109 | dma_addr_t request_daddr; | |
110 | dma_addr_t zero_scatter_daddr; | |
111 | ||
112 | unsigned int num_sg_entries; /* returned by pci_alloc_sg */ | |
113 | unsigned int request_alloc_size; /* size of block from dma_pool_alloc */ | |
114 | ||
115 | /** Note: "io_request_completion" is completed in two different ways | |
116 | * depending on whether this is a TMF or regular request. | |
117 | * - TMF requests are completed in the thread that started them; | |
118 | * - regular requests are completed in the request completion callback | |
119 | * function. | |
120 | * This difference in operation allows the aborter of a TMF request | |
121 | * to be sure that once the TMF request completes, the I/O that the | |
122 | * TMF was aborting is guaranteed to have completed. | |
123 | */ | |
124 | struct completion *io_request_completion; | |
125 | }; | |
126 | ||
127 | /** | |
128 | * This function gets the status of the request object. | |
129 | * @request: This parameter points to the isci_request object | |
130 | * | |
131 | * status of the object as a isci_request_status enum. | |
132 | */ | |
133 | static inline | |
134 | enum isci_request_status isci_request_get_state( | |
135 | struct isci_request *isci_request) | |
136 | { | |
137 | BUG_ON(isci_request == NULL); | |
138 | ||
139 | /*probably a bad sign... */ | |
140 | if (isci_request->status == unallocated) | |
141 | dev_warn(&isci_request->isci_host->pdev->dev, | |
142 | "%s: isci_request->status == unallocated\n", | |
143 | __func__); | |
144 | ||
145 | return isci_request->status; | |
146 | } | |
147 | ||
148 | ||
149 | /** | |
150 | * isci_request_change_state() - This function sets the status of the request | |
151 | * object. | |
152 | * @request: This parameter points to the isci_request object | |
153 | * @status: This Parameter is the new status of the object | |
154 | * | |
155 | */ | |
156 | static inline enum isci_request_status isci_request_change_state( | |
157 | struct isci_request *isci_request, | |
158 | enum isci_request_status status) | |
159 | { | |
160 | enum isci_request_status old_state; | |
161 | unsigned long flags; | |
162 | ||
163 | dev_dbg(&isci_request->isci_host->pdev->dev, | |
164 | "%s: isci_request = %p, state = 0x%x\n", | |
165 | __func__, | |
166 | isci_request, | |
167 | status); | |
168 | ||
169 | BUG_ON(isci_request == NULL); | |
170 | ||
171 | spin_lock_irqsave(&isci_request->state_lock, flags); | |
172 | old_state = isci_request->status; | |
173 | isci_request->status = status; | |
174 | spin_unlock_irqrestore(&isci_request->state_lock, flags); | |
175 | ||
176 | return old_state; | |
177 | } | |
178 | ||
179 | /** | |
180 | * isci_request_change_started_to_newstate() - This function sets the status of | |
181 | * the request object. | |
182 | * @request: This parameter points to the isci_request object | |
183 | * @status: This Parameter is the new status of the object | |
184 | * | |
185 | * state previous to any change. | |
186 | */ | |
187 | static inline enum isci_request_status isci_request_change_started_to_newstate( | |
188 | struct isci_request *isci_request, | |
189 | struct completion *completion_ptr, | |
190 | enum isci_request_status newstate) | |
191 | { | |
192 | enum isci_request_status old_state; | |
193 | unsigned long flags; | |
194 | ||
195 | BUG_ON(isci_request == NULL); | |
196 | ||
197 | spin_lock_irqsave(&isci_request->state_lock, flags); | |
198 | ||
199 | old_state = isci_request->status; | |
200 | ||
201 | if (old_state == started) { | |
202 | BUG_ON(isci_request->io_request_completion != NULL); | |
203 | ||
204 | isci_request->io_request_completion = completion_ptr; | |
205 | isci_request->status = newstate; | |
206 | } | |
207 | spin_unlock_irqrestore(&isci_request->state_lock, flags); | |
208 | ||
209 | dev_dbg(&isci_request->isci_host->pdev->dev, | |
210 | "%s: isci_request = %p, old_state = 0x%x\n", | |
211 | __func__, | |
212 | isci_request, | |
213 | old_state); | |
214 | ||
215 | return old_state; | |
216 | } | |
217 | ||
218 | /** | |
219 | * isci_request_change_started_to_aborted() - This function sets the status of | |
220 | * the request object. | |
221 | * @request: This parameter points to the isci_request object | |
222 | * @completion_ptr: This parameter is saved as the kernel completion structure | |
223 | * signalled when the old request completes. | |
224 | * | |
225 | * state previous to any change. | |
226 | */ | |
227 | static inline enum isci_request_status isci_request_change_started_to_aborted( | |
228 | struct isci_request *isci_request, | |
229 | struct completion *completion_ptr) | |
230 | { | |
231 | return isci_request_change_started_to_newstate( | |
232 | isci_request, completion_ptr, aborted | |
233 | ); | |
234 | } | |
235 | /** | |
236 | * isci_request_free() - This function frees the request object. | |
237 | * @isci_host: This parameter specifies the ISCI host object | |
238 | * @isci_request: This parameter points to the isci_request object | |
239 | * | |
240 | */ | |
241 | static inline void isci_request_free( | |
242 | struct isci_host *isci_host, | |
243 | struct isci_request *isci_request) | |
244 | { | |
245 | BUG_ON(isci_request == NULL); | |
246 | ||
247 | /* release the dma memory if we fail. */ | |
248 | dma_pool_free(isci_host->dma_pool, isci_request, | |
249 | isci_request->request_daddr); | |
250 | } | |
251 | ||
252 | ||
253 | /* #define ISCI_REQUEST_VALIDATE_ACCESS | |
254 | */ | |
255 | ||
256 | #ifdef ISCI_REQUEST_VALIDATE_ACCESS | |
257 | ||
258 | static inline | |
259 | struct sas_task *isci_request_access_task(struct isci_request *isci_request) | |
260 | { | |
261 | BUG_ON(isci_request->ttype != io_task); | |
262 | return isci_request->ttype_ptr.io_task_ptr; | |
263 | } | |
264 | ||
265 | static inline | |
266 | struct isci_tmf *isci_request_access_tmf(struct isci_request *isci_request) | |
267 | { | |
268 | BUG_ON(isci_request->ttype != tmf_task); | |
269 | return isci_request->ttype_ptr.tmf_task_ptr; | |
270 | } | |
271 | ||
272 | #else /* not ISCI_REQUEST_VALIDATE_ACCESS */ | |
273 | ||
274 | #define isci_request_access_task(RequestPtr) \ | |
275 | ((RequestPtr)->ttype_ptr.io_task_ptr) | |
276 | ||
277 | #define isci_request_access_tmf(RequestPtr) \ | |
278 | ((RequestPtr)->ttype_ptr.tmf_task_ptr) | |
279 | ||
280 | #endif /* not ISCI_REQUEST_VALIDATE_ACCESS */ | |
281 | ||
282 | ||
283 | int isci_request_alloc_tmf( | |
284 | struct isci_host *isci_host, | |
285 | struct isci_tmf *isci_tmf, | |
286 | struct isci_request **isci_request, | |
287 | struct isci_remote_device *isci_device, | |
288 | gfp_t gfp_flags); | |
289 | ||
290 | ||
291 | int isci_request_execute( | |
292 | struct isci_host *isci_host, | |
293 | struct sas_task *task, | |
294 | struct isci_request **request, | |
295 | gfp_t gfp_flags); | |
296 | ||
297 | /** | |
298 | * isci_request_unmap_sgl() - This function unmaps the DMA address of a given | |
299 | * sgl | |
300 | * @request: This parameter points to the isci_request object | |
301 | * @*pdev: This Parameter is the pci_device struct for the controller | |
302 | * | |
303 | */ | |
304 | static inline void isci_request_unmap_sgl( | |
305 | struct isci_request *request, | |
306 | struct pci_dev *pdev) | |
307 | { | |
308 | struct sas_task *task = isci_request_access_task(request); | |
309 | ||
310 | dev_dbg(&request->isci_host->pdev->dev, | |
311 | "%s: request = %p, task = %p,\n" | |
312 | "task->data_dir = %d, is_sata = %d\n ", | |
313 | __func__, | |
314 | request, | |
315 | task, | |
316 | task->data_dir, | |
317 | sas_protocol_ata(task->task_proto)); | |
318 | ||
319 | if ((task->data_dir != PCI_DMA_NONE) && | |
320 | !sas_protocol_ata(task->task_proto)) { | |
321 | if (task->num_scatter == 0) | |
322 | /* 0 indicates a single dma address */ | |
323 | dma_unmap_single( | |
324 | &pdev->dev, | |
325 | request->zero_scatter_daddr, | |
326 | task->total_xfer_len, | |
327 | task->data_dir | |
328 | ); | |
329 | ||
330 | else /* unmap the sgl dma addresses */ | |
331 | dma_unmap_sg( | |
332 | &pdev->dev, | |
333 | task->scatter, | |
334 | request->num_sg_entries, | |
335 | task->data_dir | |
336 | ); | |
337 | } | |
338 | } | |
339 | ||
340 | ||
341 | void isci_request_io_request_complete( | |
342 | struct isci_host *isci_host, | |
343 | struct isci_request *request, | |
344 | enum sci_io_status completion_status); | |
345 | ||
346 | u32 isci_request_io_request_get_transfer_length( | |
347 | struct isci_request *request); | |
348 | ||
82d29928 | 349 | enum dma_data_direction isci_request_io_request_get_data_direction(struct isci_request *req); |
6f231dda DW |
350 | |
351 | /** | |
352 | * isci_request_io_request_get_next_sge() - This function is called by the sci | |
353 | * core to retrieve the next sge for a given request. | |
354 | * @request: This parameter is the isci_request object. | |
355 | * @current_sge_address: This parameter is the last sge retrieved by the sci | |
356 | * core for this request. | |
357 | * | |
358 | * pointer to the next sge for specified request. | |
359 | */ | |
360 | static inline void *isci_request_io_request_get_next_sge( | |
361 | struct isci_request *request, | |
362 | void *current_sge_address) | |
363 | { | |
364 | struct sas_task *task = isci_request_access_task(request); | |
365 | void *ret = NULL; | |
366 | ||
367 | dev_dbg(&request->isci_host->pdev->dev, | |
368 | "%s: request = %p, " | |
369 | "current_sge_address = %p, " | |
370 | "num_scatter = %d\n", | |
371 | __func__, | |
372 | request, | |
373 | current_sge_address, | |
374 | task->num_scatter); | |
375 | ||
376 | if (!current_sge_address) /* First time through.. */ | |
377 | ret = task->scatter; /* always task->scatter */ | |
378 | else if (task->num_scatter == 0) /* Next element, if num_scatter == 0 */ | |
379 | ret = NULL; /* there is only one element. */ | |
380 | else | |
381 | ret = sg_next(current_sge_address); /* sg_next returns NULL | |
382 | * for the last element | |
383 | */ | |
384 | ||
385 | dev_dbg(&request->isci_host->pdev->dev, | |
386 | "%s: next sge address = %p\n", | |
387 | __func__, | |
388 | ret); | |
389 | ||
390 | return ret; | |
391 | } | |
392 | ||
393 | dma_addr_t isci_request_sge_get_address_field( | |
394 | struct isci_request *request, | |
395 | void *sge_address); | |
396 | ||
397 | u32 isci_request_sge_get_length_field( | |
398 | struct isci_request *request, | |
399 | void *sge_address); | |
400 | ||
401 | void *isci_request_ssp_io_request_get_cdb_address( | |
402 | struct isci_request *request); | |
403 | ||
404 | u32 isci_request_ssp_io_request_get_cdb_length( | |
405 | struct isci_request *request); | |
406 | ||
407 | u32 isci_request_ssp_io_request_get_lun( | |
408 | struct isci_request *request); | |
409 | ||
410 | u32 isci_request_ssp_io_request_get_task_attribute( | |
411 | struct isci_request *request); | |
412 | ||
413 | u32 isci_request_ssp_io_request_get_command_priority( | |
414 | struct isci_request *request); | |
415 | ||
416 | ||
417 | ||
418 | ||
419 | ||
420 | void isci_terminate_pending_requests( | |
421 | struct isci_host *isci_host, | |
422 | struct isci_remote_device *isci_device, | |
423 | enum isci_request_status new_request_state); | |
424 | ||
425 | ||
426 | ||
427 | ||
428 | #endif /* !defined(_ISCI_REQUEST_H_) */ |