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