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 */
57void
58scif_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 */
84uint32_t
85scif_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 */
111uint8_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 */
131uint16_t
132scif_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 */
149void *
150scif_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 */
169uint32_t
170scif_cb_task_request_get_response_data_length(void * scif_user_task_request)
171{
172
173	return (sizeof(struct scsi_sense_data));
174}
175
176void
177isci_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
280