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