xref: /freebsd/sys/dev/isci/isci_task_request.c (revision 3e11bd9e2a2b1cbd4283c87c93e3cc75e3f2dacb)
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$");
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  */
55 void
56 scif_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  */
82 uint32_t
83 scif_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  */
109 uint8_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  */
129 uint16_t
130 scif_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  */
147 void *
148 scif_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  */
167 uint32_t
168 scif_cb_task_request_get_response_data_length(void * scif_user_task_request)
169 {
170 
171 	return (sizeof(struct scsi_sense_data));
172 }
173 
174 void
175 isci_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(isci_controller,
214 			    isci_remote_device->domain, isci_remote_device);
215 		} else {
216 			retry_task = TRUE;
217 			isci_log_message(0, "ISCI",
218 			    "task timeout - retrying\n");
219 		}
220 		break;
221 
222 	case SCI_TASK_FAILURE:
223 	case SCI_TASK_FAILURE_UNSUPPORTED_PROTOCOL:
224 	case SCI_TASK_FAILURE_INVALID_TAG:
225 	case SCI_TASK_FAILURE_CONTROLLER_SPECIFIC_ERR:
226 	case SCI_TASK_FAILURE_TERMINATED:
227 	case SCI_TASK_FAILURE_INVALID_PARAMETER_VALUE:
228 		isci_log_message(0, "ISCI",
229 		    "unhandled task completion code 0x%x\n", completion_status);
230 		break;
231 
232 	default:
233 		isci_log_message(0, "ISCI",
234 		    "unhandled task completion code 0x%x\n", completion_status);
235 		break;
236 	}
237 
238 	if (isci_controller->is_frozen == TRUE) {
239 		isci_controller->is_frozen = FALSE;
240 		xpt_release_simq(isci_controller->sim, TRUE);
241 	}
242 
243 	sci_pool_put(isci_controller->request_pool,
244 	    (struct ISCI_REQUEST *)isci_task_request);
245 
246 	/* Make sure we release the device queue, since it may have been frozen
247 	 *  if someone tried to start an I/O while the task was in progress.
248 	 */
249 	isci_remote_device_release_device_queue(isci_remote_device);
250 
251 	if (retry_task == TRUE)
252 		isci_remote_device_reset(isci_remote_device, ccb);
253 	else {
254 		pending_remote_device = sci_fast_list_remove_head(
255 		    &isci_controller->pending_device_reset_list);
256 
257 		if (pending_remote_device != NULL) {
258 			/* Any resets that were triggered from an XPT_RESET_DEV
259 			 *  CCB are never put in the pending list if the request
260 			 *  pool is empty - they are given back to CAM to be
261 			 *  requeued.  So we will alawys pass NULL here,
262 			 *  denoting that there is no CCB associated with the
263 			 *  device reset.
264 			 */
265 			isci_remote_device_reset(pending_remote_device, NULL);
266 		} else if (ccb != NULL) {
267 			/* There was a CCB associated with this reset, so mark
268 			 *  it complete and return it to CAM.
269 			 */
270 			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
271 			ccb->ccb_h.status |= CAM_REQ_CMP;
272 			xpt_done(ccb);
273 		}
274 	}
275 }
276 
277