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 | */ | |
cc3dbd0a | 55 | #ifndef _ISCI_TASK_H_ |
6f231dda DW |
56 | #define _ISCI_TASK_H_ |
57 | ||
ed8a72d1 | 58 | #include <scsi/sas_ata.h> |
ce2b3261 | 59 | #include "host.h" |
ed8a72d1 | 60 | |
6f231dda | 61 | struct isci_request; |
6f231dda DW |
62 | |
63 | /** | |
64 | * enum isci_tmf_cb_state - This enum defines the possible states in which the | |
65 | * TMF callback function is invoked during the TMF execution process. | |
66 | * | |
67 | * | |
68 | */ | |
69 | enum isci_tmf_cb_state { | |
70 | ||
71 | isci_tmf_init_state = 0, | |
72 | isci_tmf_started, | |
73 | isci_tmf_timed_out | |
74 | }; | |
75 | ||
76 | /** | |
77 | * enum isci_tmf_function_codes - This enum defines the possible preparations | |
78 | * of task management requests. | |
79 | * | |
80 | * | |
81 | */ | |
82 | enum isci_tmf_function_codes { | |
83 | ||
84 | isci_tmf_func_none = 0, | |
85 | isci_tmf_ssp_task_abort = TMF_ABORT_TASK, | |
86 | isci_tmf_ssp_lun_reset = TMF_LU_RESET, | |
87 | isci_tmf_sata_srst_high = TMF_LU_RESET + 0x100, /* Non SCSI */ | |
88 | isci_tmf_sata_srst_low = TMF_LU_RESET + 0x101 /* Non SCSI */ | |
89 | }; | |
90 | /** | |
91 | * struct isci_tmf - This class represents the task management object which | |
92 | * acts as an interface to libsas for processing task management requests | |
93 | * | |
94 | * | |
95 | */ | |
96 | struct isci_tmf { | |
97 | ||
98 | struct completion *complete; | |
99 | enum sas_protocol proto; | |
100 | union { | |
af5ae893 | 101 | struct ssp_response_iu resp_iu; |
6f231dda DW |
102 | struct dev_to_host_fis d2h_fis; |
103 | } resp; | |
104 | unsigned char lun[8]; | |
105 | u16 io_tag; | |
106 | struct isci_remote_device *device; | |
107 | enum isci_tmf_function_codes tmf_code; | |
108 | int status; | |
109 | ||
110 | struct isci_timer *timeout_timer; | |
111 | ||
112 | /* The optional callback function allows the user process to | |
113 | * track the TMF transmit / timeout conditions. | |
114 | */ | |
115 | void (*cb_state_func)( | |
116 | enum isci_tmf_cb_state, | |
117 | struct isci_tmf *, void *); | |
118 | void *cb_data; | |
119 | ||
120 | }; | |
121 | ||
af5ae893 | 122 | static inline void isci_print_tmf(struct isci_tmf *tmf) |
6f231dda DW |
123 | { |
124 | if (SAS_PROTOCOL_SATA == tmf->proto) | |
125 | dev_dbg(&tmf->device->isci_port->isci_host->pdev->dev, | |
126 | "%s: status = %x\n" | |
127 | "tmf->resp.d2h_fis.status = %x\n" | |
128 | "tmf->resp.d2h_fis.error = %x\n", | |
129 | __func__, | |
130 | tmf->status, | |
131 | tmf->resp.d2h_fis.status, | |
132 | tmf->resp.d2h_fis.error); | |
133 | else | |
134 | dev_dbg(&tmf->device->isci_port->isci_host->pdev->dev, | |
135 | "%s: status = %x\n" | |
136 | "tmf->resp.resp_iu.data_present = %x\n" | |
137 | "tmf->resp.resp_iu.status = %x\n" | |
138 | "tmf->resp.resp_iu.data_length = %x\n" | |
139 | "tmf->resp.resp_iu.data[0] = %x\n" | |
140 | "tmf->resp.resp_iu.data[1] = %x\n" | |
141 | "tmf->resp.resp_iu.data[2] = %x\n" | |
142 | "tmf->resp.resp_iu.data[3] = %x\n", | |
143 | __func__, | |
144 | tmf->status, | |
af5ae893 | 145 | tmf->resp.resp_iu.datapres, |
6f231dda | 146 | tmf->resp.resp_iu.status, |
af5ae893 DJ |
147 | be32_to_cpu(tmf->resp.resp_iu.response_data_len), |
148 | tmf->resp.resp_iu.resp_data[0], | |
149 | tmf->resp.resp_iu.resp_data[1], | |
150 | tmf->resp.resp_iu.resp_data[2], | |
151 | tmf->resp.resp_iu.resp_data[3]); | |
6f231dda DW |
152 | } |
153 | ||
154 | ||
155 | int isci_task_execute_task( | |
156 | struct sas_task *task, | |
157 | int num, | |
158 | gfp_t gfp_flags); | |
159 | ||
160 | int isci_task_abort_task( | |
161 | struct sas_task *task); | |
162 | ||
163 | int isci_task_abort_task_set( | |
164 | struct domain_device *d_device, | |
165 | u8 *lun); | |
166 | ||
167 | int isci_task_clear_aca( | |
168 | struct domain_device *d_device, | |
169 | u8 *lun); | |
170 | ||
171 | int isci_task_clear_task_set( | |
172 | struct domain_device *d_device, | |
173 | u8 *lun); | |
174 | ||
175 | int isci_task_query_task( | |
176 | struct sas_task *task); | |
177 | ||
178 | int isci_task_lu_reset( | |
179 | struct domain_device *d_device, | |
180 | u8 *lun); | |
181 | ||
182 | int isci_task_clear_nexus_port( | |
183 | struct asd_sas_port *port); | |
184 | ||
185 | int isci_task_clear_nexus_ha( | |
186 | struct sas_ha_struct *ha); | |
187 | ||
188 | int isci_task_I_T_nexus_reset( | |
189 | struct domain_device *d_device); | |
190 | ||
191 | void isci_task_request_complete( | |
192 | struct isci_host *isci_host, | |
193 | struct isci_request *request, | |
194 | enum sci_task_status completion_status); | |
195 | ||
196 | u16 isci_task_ssp_request_get_io_tag_to_manage( | |
197 | struct isci_request *request); | |
198 | ||
199 | u8 isci_task_ssp_request_get_function( | |
200 | struct isci_request *request); | |
201 | ||
6f231dda DW |
202 | |
203 | void *isci_task_ssp_request_get_response_data_address( | |
204 | struct isci_request *request); | |
205 | ||
206 | u32 isci_task_ssp_request_get_response_data_length( | |
207 | struct isci_request *request); | |
208 | ||
209 | int isci_queuecommand( | |
210 | struct scsi_cmnd *scsi_cmd, | |
211 | void (*donefunc)(struct scsi_cmnd *)); | |
212 | ||
213 | int isci_bus_reset_handler(struct scsi_cmnd *cmd); | |
214 | ||
215 | void isci_task_build_tmf( | |
216 | struct isci_tmf *tmf, | |
c3f42feb JS |
217 | struct isci_remote_device *isci_device, |
218 | enum isci_tmf_function_codes code, | |
219 | void (*tmf_sent_cb)(enum isci_tmf_cb_state, | |
220 | struct isci_tmf *, | |
221 | void *), | |
222 | void *cb_data); | |
223 | ||
6f231dda DW |
224 | |
225 | int isci_task_execute_tmf( | |
226 | struct isci_host *isci_host, | |
227 | struct isci_tmf *tmf, | |
228 | unsigned long timeout_ms); | |
229 | ||
230 | /** | |
231 | * enum isci_completion_selection - This enum defines the possible actions to | |
232 | * take with respect to a given request's notification back to libsas. | |
233 | * | |
234 | * | |
235 | */ | |
236 | enum isci_completion_selection { | |
237 | ||
238 | isci_perform_normal_io_completion, /* Normal notify (task_done) */ | |
239 | isci_perform_aborted_io_completion, /* No notification. */ | |
240 | isci_perform_error_io_completion /* Use sas_task_abort */ | |
241 | }; | |
242 | ||
243 | static inline void isci_set_task_doneflags( | |
244 | struct sas_task *task) | |
245 | { | |
246 | /* Since no futher action will be taken on this task, | |
247 | * make sure to mark it complete from the lldd perspective. | |
248 | */ | |
249 | task->task_state_flags |= SAS_TASK_STATE_DONE; | |
250 | task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; | |
251 | task->task_state_flags &= ~SAS_TASK_STATE_PENDING; | |
252 | } | |
253 | /** | |
254 | * isci_task_all_done() - This function clears the task bits to indicate the | |
255 | * LLDD is done with the task. | |
256 | * | |
257 | * | |
258 | */ | |
259 | static inline void isci_task_all_done( | |
260 | struct sas_task *task) | |
261 | { | |
262 | unsigned long flags; | |
263 | ||
264 | /* Since no futher action will be taken on this task, | |
265 | * make sure to mark it complete from the lldd perspective. | |
266 | */ | |
267 | spin_lock_irqsave(&task->task_state_lock, flags); | |
268 | isci_set_task_doneflags(task); | |
269 | spin_unlock_irqrestore(&task->task_state_lock, flags); | |
270 | } | |
271 | ||
272 | /** | |
273 | * isci_task_set_completion_status() - This function sets the completion status | |
274 | * for the request. | |
275 | * @task: This parameter is the completed request. | |
276 | * @response: This parameter is the response code for the completed task. | |
277 | * @status: This parameter is the status code for the completed task. | |
278 | * | |
ec6c9638 JS |
279 | * @return The new notification mode for the request. |
280 | */ | |
281 | static inline enum isci_completion_selection | |
282 | isci_task_set_completion_status( | |
6f231dda DW |
283 | struct sas_task *task, |
284 | enum service_response response, | |
285 | enum exec_status status, | |
286 | enum isci_completion_selection task_notification_selection) | |
287 | { | |
288 | unsigned long flags; | |
289 | ||
290 | spin_lock_irqsave(&task->task_state_lock, flags); | |
291 | ||
ec6c9638 JS |
292 | /* If a device reset is being indicated, make sure the I/O |
293 | * is in the error path. | |
294 | */ | |
aa145102 | 295 | if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) { |
aa145102 JS |
296 | /* Fail the I/O to make sure it goes into the error path. */ |
297 | response = SAS_TASK_UNDELIVERED; | |
298 | status = SAM_STAT_TASK_ABORTED; | |
299 | ||
ec6c9638 | 300 | task_notification_selection = isci_perform_error_io_completion; |
aa145102 JS |
301 | } |
302 | task->task_status.resp = response; | |
303 | task->task_status.stat = status; | |
ec6c9638 JS |
304 | |
305 | switch (task_notification_selection) { | |
ce0b89f3 DW |
306 | case isci_perform_aborted_io_completion: |
307 | /* This path can occur with task-managed requests as well as | |
308 | * requests terminated because of LUN or device resets. | |
309 | */ | |
310 | /* Fall through to the normal case... */ | |
311 | case isci_perform_normal_io_completion: | |
312 | /* Normal notification (task_done) */ | |
313 | isci_set_task_doneflags(task); | |
314 | break; | |
315 | default: | |
316 | WARN_ONCE(1, "unknown task_notification_selection: %d\n", | |
317 | task_notification_selection); | |
318 | /* Fall through to the error case... */ | |
319 | case isci_perform_error_io_completion: | |
320 | /* Use sas_task_abort */ | |
321 | /* Leave SAS_TASK_STATE_DONE clear | |
322 | * Leave SAS_TASK_AT_INITIATOR set. | |
323 | */ | |
324 | break; | |
ec6c9638 | 325 | } |
6f231dda DW |
326 | |
327 | spin_unlock_irqrestore(&task->task_state_lock, flags); | |
ec6c9638 JS |
328 | |
329 | return task_notification_selection; | |
330 | ||
6f231dda | 331 | } |
ed8a72d1 JS |
332 | /** |
333 | * isci_execpath_callback() - This function is called from the task | |
334 | * execute path when the task needs to callback libsas about the submit-time | |
335 | * task failure. The callback occurs either through the task's done function | |
336 | * or through sas_task_abort. In the case of regular non-discovery SATA/STP I/O | |
337 | * requests, libsas takes the host lock before calling execute task. Therefore | |
338 | * in this situation the host lock must be managed before calling the func. | |
339 | * | |
340 | * @ihost: This parameter is the controller to which the I/O request was sent. | |
341 | * @task: This parameter is the I/O request. | |
342 | * @func: This parameter is the function to call in the correct context. | |
343 | * @status: This parameter is the status code for the completed task. | |
344 | * | |
345 | */ | |
5b3f2bd8 DW |
346 | static inline void isci_execpath_callback(struct isci_host *ihost, |
347 | struct sas_task *task, | |
348 | void (*func)(struct sas_task *)) | |
ed8a72d1 | 349 | { |
5b3f2bd8 DW |
350 | struct domain_device *dev = task->dev; |
351 | ||
352 | if (dev_is_sata(dev) && task->uldd_task) { | |
353 | unsigned long flags; | |
ed8a72d1 | 354 | |
ed8a72d1 | 355 | /* Since we are still in the submit path, and since |
5b3f2bd8 DW |
356 | * libsas takes the host lock on behalf of SATA |
357 | * devices before I/O starts (in the non-discovery case), | |
358 | * we need to unlock before we can call the callback function. | |
359 | */ | |
ed8a72d1 | 360 | raw_local_irq_save(flags); |
5b3f2bd8 | 361 | spin_unlock(dev->sata_dev.ap->lock); |
ed8a72d1 | 362 | func(task); |
5b3f2bd8 | 363 | spin_lock(dev->sata_dev.ap->lock); |
ed8a72d1 JS |
364 | raw_local_irq_restore(flags); |
365 | } else | |
366 | func(task); | |
367 | } | |
6f231dda | 368 | #endif /* !defined(_SCI_TASK_H_) */ |