]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/isci/isci_task_request.c
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / sys / dev / isci / isci_task_request.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * BSD LICENSE
5  *
6  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  *   * Redistributions of source code must retain the above copyright
14  *     notice, this list of conditions and the following disclaimer.
15  *   * Redistributions in binary form must reproduce the above copyright
16  *     notice, this list of conditions and the following disclaimer in
17  *     the documentation and/or other materials provided with the
18  *     distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <dev/isci/isci.h>
37
38 #include <dev/isci/scil/scif_controller.h>
39 #include <dev/isci/scil/scif_user_callback.h>
40
41 /**
42  * @brief This user callback will inform the user that a task management
43  *        request completed.
44  *
45  * @param[in]  controller This parameter specifies the controller on
46  *             which the task management request is completing.
47  * @param[in]  remote_device This parameter specifies the remote device on
48  *             which this task management request is completing.
49  * @param[in]  task_request This parameter specifies the task management
50  *             request that has completed.
51  * @param[in]  completion_status This parameter specifies the results of
52  *             the IO request operation.  SCI_TASK_SUCCESS indicates
53  *             successful completion.
54  *
55  * @return none
56  */
57 void
58 scif_cb_task_request_complete(SCI_CONTROLLER_HANDLE_T controller,
59     SCI_REMOTE_DEVICE_HANDLE_T remote_device,
60     SCI_TASK_REQUEST_HANDLE_T task_request, SCI_TASK_STATUS completion_status)
61 {
62
63         scif_controller_complete_task(controller, remote_device, task_request);
64         isci_task_request_complete(controller, remote_device, task_request,
65             completion_status);
66 }
67
68 /**
69  * @brief This method returns the Logical Unit to be utilized for this
70  *        task management request.
71  *
72  * @note The contents of the value returned from this callback are defined
73  *       by the protocol standard (e.g. T10 SAS specification).  Please
74  *       refer to the transport task information unit description
75  *       in the associated standard.
76  *
77  * @param[in] scif_user_task_request This parameter points to the user's
78  *            task request object.  It is a cookie that allows the user to
79  *            provide the necessary information for this callback.
80  *
81  * @return This method returns the LUN associated with this request.
82  * @todo This should be U64?
83  */
84 uint32_t
85 scif_cb_task_request_get_lun(void * scif_user_task_request)
86 {
87
88         /* Currently we are only doing hard resets, not LUN resets.  So
89          *  always returning 0 is OK here, since LUN doesn't matter for
90          *  a hard device reset.
91          */
92         return (0);
93 }
94
95 /**
96  * @brief This method returns the task management function to be utilized
97  *        for this task request.
98  *
99  * @note The contents of the value returned from this callback are defined
100  *       by the protocol standard (e.g. T10 SAS specification).  Please
101  *       refer to the transport task information unit description
102  *       in the associated standard.
103  *
104  * @param[in] scif_user_task_request This parameter points to the user's
105  *            task request object.  It is a cookie that allows the user to
106  *            provide the necessary information for this callback.
107  *
108  * @return This method returns an unsigned byte representing the task
109  *         management function to be performed.
110  */
111 uint8_t scif_cb_task_request_get_function(void * scif_user_task_request)
112 {
113         /* SCIL supports many types of task management functions, but this
114          *  driver only uses HARD_RESET.
115          */
116         return (SCI_SAS_HARD_RESET);
117 }
118
119 /**
120  * @brief This method returns the task management IO tag to be managed.
121  *        Depending upon the task management function the value returned
122  *        from this method may be ignored.
123  *
124  * @param[in] scif_user_task_request This parameter points to the user's
125  *            task request object.  It is a cookie that allows the user to
126  *            provide the necessary information for this callback.
127  *
128  * @return This method returns an unsigned 16-bit word depicting the IO
129  *         tag to be managed.
130  */
131 uint16_t
132 scif_cb_task_request_get_io_tag_to_manage(void * scif_user_task_request)
133 {
134
135         return (0);
136 }
137
138 /**
139  * @brief This callback method asks the user to provide the virtual
140  *        address of the response data buffer for the supplied IO request.
141  *
142  * @param[in] scif_user_task_request This parameter points to the user's
143  *            task request object.  It is a cookie that allows the user to
144  *            provide the necessary information for this callback.
145  *
146  * @return This method returns the virtual address for the response data buffer
147  *         associated with this IO request.
148  */
149 void *
150 scif_cb_task_request_get_response_data_address(void * scif_user_task_request)
151 {
152         struct ISCI_TASK_REQUEST *task_request =
153             (struct ISCI_TASK_REQUEST *)scif_user_task_request;
154
155         return (&task_request->sense_data);
156 }
157
158 /**
159  * @brief This callback method asks the user to provide the length of the
160  *        response data buffer for the supplied IO request.
161  *
162  * @param[in] scif_user_task_request This parameter points to the user's
163  *            task request object.  It is a cookie that allows the user to
164  *            provide the necessary information for this callback.
165  *
166  * @return This method returns the length of the response buffer data
167  *         associated with this IO request.
168  */
169 uint32_t
170 scif_cb_task_request_get_response_data_length(void * scif_user_task_request)
171 {
172
173         return (sizeof(struct scsi_sense_data));
174 }
175
176 void
177 isci_task_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
178     SCI_REMOTE_DEVICE_HANDLE_T remote_device,
179     SCI_TASK_REQUEST_HANDLE_T task_request, SCI_TASK_STATUS completion_status)
180 {
181         struct ISCI_TASK_REQUEST *isci_task_request =
182                 (struct ISCI_TASK_REQUEST *)sci_object_get_association(task_request);
183         struct ISCI_CONTROLLER *isci_controller =
184                 (struct ISCI_CONTROLLER *)sci_object_get_association(scif_controller);
185         struct ISCI_REMOTE_DEVICE *isci_remote_device =
186                 (struct ISCI_REMOTE_DEVICE *)sci_object_get_association(remote_device);
187         struct ISCI_REMOTE_DEVICE *pending_remote_device;
188         BOOL retry_task = FALSE;
189         union ccb *ccb = isci_task_request->ccb;
190
191         isci_remote_device->is_resetting = FALSE;
192
193         switch ((int)completion_status) {
194         case SCI_TASK_SUCCESS:
195         case SCI_TASK_FAILURE_RESPONSE_VALID:
196                 break;
197
198         case SCI_TASK_FAILURE_INVALID_STATE:
199                 retry_task = TRUE;
200                 isci_log_message(0, "ISCI",
201                     "task failure (invalid state) - retrying\n");
202                 break;
203
204         case SCI_TASK_FAILURE_INSUFFICIENT_RESOURCES:
205                 retry_task = TRUE;
206                 isci_log_message(0, "ISCI",
207                     "task failure (insufficient resources) - retrying\n");
208                 break;
209
210         case SCI_FAILURE_TIMEOUT:
211                 if (isci_controller->fail_on_task_timeout) {
212                         retry_task = FALSE;
213                         isci_log_message(0, "ISCI",
214                             "task timeout - not retrying\n");
215                         scif_cb_domain_device_removed(scif_controller,
216                             isci_remote_device->domain->sci_object,
217                             remote_device);
218                 } else {
219                         retry_task = TRUE;
220                         isci_log_message(0, "ISCI",
221                             "task timeout - retrying\n");
222                 }
223                 break;
224
225         case SCI_TASK_FAILURE:
226         case SCI_TASK_FAILURE_UNSUPPORTED_PROTOCOL:
227         case SCI_TASK_FAILURE_INVALID_TAG:
228         case SCI_TASK_FAILURE_CONTROLLER_SPECIFIC_ERR:
229         case SCI_TASK_FAILURE_TERMINATED:
230         case SCI_TASK_FAILURE_INVALID_PARAMETER_VALUE:
231                 isci_log_message(0, "ISCI",
232                     "unhandled task completion code 0x%x\n", completion_status);
233                 break;
234
235         default:
236                 isci_log_message(0, "ISCI",
237                     "unhandled task completion code 0x%x\n", completion_status);
238                 break;
239         }
240
241         if (isci_controller->is_frozen == TRUE) {
242                 isci_controller->is_frozen = FALSE;
243                 xpt_release_simq(isci_controller->sim, TRUE);
244         }
245
246         sci_pool_put(isci_controller->request_pool,
247             (struct ISCI_REQUEST *)isci_task_request);
248
249         /* Make sure we release the device queue, since it may have been frozen
250          *  if someone tried to start an I/O while the task was in progress.
251          */
252         isci_remote_device_release_device_queue(isci_remote_device);
253
254         if (retry_task == TRUE)
255                 isci_remote_device_reset(isci_remote_device, ccb);
256         else {
257                 pending_remote_device = sci_fast_list_remove_head(
258                     &isci_controller->pending_device_reset_list);
259
260                 if (pending_remote_device != NULL) {
261                         /* Any resets that were triggered from an XPT_RESET_DEV
262                          *  CCB are never put in the pending list if the request
263                          *  pool is empty - they are given back to CAM to be
264                          *  requeued.  So we will alawys pass NULL here,
265                          *  denoting that there is no CCB associated with the
266                          *  device reset.
267                          */
268                         isci_remote_device_reset(pending_remote_device, NULL);
269                 } else if (ccb != NULL) {
270                         /* There was a CCB associated with this reset, so mark
271                          *  it complete and return it to CAM.
272                          */
273                         ccb->ccb_h.status &= ~CAM_STATUS_MASK;
274                         ccb->ccb_h.status |= CAM_REQ_CMP;
275                         xpt_done(ccb);
276                 }
277         }
278 }
279