diff options
Diffstat (limited to 'drivers/scsi/isci/request.h')
-rw-r--r-- | drivers/scsi/isci/request.h | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h new file mode 100644 index 000000000000..5079d4a7c41b --- /dev/null +++ b/drivers/scsi/isci/request.h | |||
@@ -0,0 +1,429 @@ | |||
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 | |||
349 | SCI_IO_REQUEST_DATA_DIRECTION isci_request_io_request_get_data_direction( | ||
350 | struct isci_request *request); | ||
351 | |||
352 | /** | ||
353 | * isci_request_io_request_get_next_sge() - This function is called by the sci | ||
354 | * core to retrieve the next sge for a given request. | ||
355 | * @request: This parameter is the isci_request object. | ||
356 | * @current_sge_address: This parameter is the last sge retrieved by the sci | ||
357 | * core for this request. | ||
358 | * | ||
359 | * pointer to the next sge for specified request. | ||
360 | */ | ||
361 | static inline void *isci_request_io_request_get_next_sge( | ||
362 | struct isci_request *request, | ||
363 | void *current_sge_address) | ||
364 | { | ||
365 | struct sas_task *task = isci_request_access_task(request); | ||
366 | void *ret = NULL; | ||
367 | |||
368 | dev_dbg(&request->isci_host->pdev->dev, | ||
369 | "%s: request = %p, " | ||
370 | "current_sge_address = %p, " | ||
371 | "num_scatter = %d\n", | ||
372 | __func__, | ||
373 | request, | ||
374 | current_sge_address, | ||
375 | task->num_scatter); | ||
376 | |||
377 | if (!current_sge_address) /* First time through.. */ | ||
378 | ret = task->scatter; /* always task->scatter */ | ||
379 | else if (task->num_scatter == 0) /* Next element, if num_scatter == 0 */ | ||
380 | ret = NULL; /* there is only one element. */ | ||
381 | else | ||
382 | ret = sg_next(current_sge_address); /* sg_next returns NULL | ||
383 | * for the last element | ||
384 | */ | ||
385 | |||
386 | dev_dbg(&request->isci_host->pdev->dev, | ||
387 | "%s: next sge address = %p\n", | ||
388 | __func__, | ||
389 | ret); | ||
390 | |||
391 | return ret; | ||
392 | } | ||
393 | |||
394 | dma_addr_t isci_request_sge_get_address_field( | ||
395 | struct isci_request *request, | ||
396 | void *sge_address); | ||
397 | |||
398 | u32 isci_request_sge_get_length_field( | ||
399 | struct isci_request *request, | ||
400 | void *sge_address); | ||
401 | |||
402 | void *isci_request_ssp_io_request_get_cdb_address( | ||
403 | struct isci_request *request); | ||
404 | |||
405 | u32 isci_request_ssp_io_request_get_cdb_length( | ||
406 | struct isci_request *request); | ||
407 | |||
408 | u32 isci_request_ssp_io_request_get_lun( | ||
409 | struct isci_request *request); | ||
410 | |||
411 | u32 isci_request_ssp_io_request_get_task_attribute( | ||
412 | struct isci_request *request); | ||
413 | |||
414 | u32 isci_request_ssp_io_request_get_command_priority( | ||
415 | struct isci_request *request); | ||
416 | |||
417 | |||
418 | |||
419 | |||
420 | |||
421 | void isci_terminate_pending_requests( | ||
422 | struct isci_host *isci_host, | ||
423 | struct isci_remote_device *isci_device, | ||
424 | enum isci_request_status new_request_state); | ||
425 | |||
426 | |||
427 | |||
428 | |||
429 | #endif /* !defined(_ISCI_REQUEST_H_) */ | ||