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 <cam/cam_periph.h> 39 #include <cam/cam_xpt_periph.h> 40 41 #include <dev/isci/scil/scif_task_request.h> 42 #include <dev/isci/scil/scif_controller.h> 43 #include <dev/isci/scil/scif_domain.h> 44 #include <dev/isci/scil/scif_user_callback.h> 45 46 #include <dev/isci/scil/scic_port.h> 47 #include <dev/isci/scil/scic_phy.h> 48 49 /** 50 * @brief This callback method informs the framework user that the remote 51 * device is ready and capable of processing IO requests. 52 * 53 * @param[in] controller This parameter specifies the controller object 54 * with which this callback is associated. 55 * @param[in] domain This parameter specifies the domain object with 56 * which this callback is associated. 57 * @param[in] remote_device This parameter specifies the device object with 58 * which this callback is associated. 59 * 60 * @return none 61 */ 62 void 63 scif_cb_remote_device_ready(SCI_CONTROLLER_HANDLE_T controller, 64 SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device) 65 { 66 struct ISCI_REMOTE_DEVICE *isci_remote_device = 67 sci_object_get_association(remote_device); 68 struct ISCI_CONTROLLER *isci_controller = 69 sci_object_get_association(controller); 70 uint32_t device_index = isci_remote_device->index; 71 72 if (isci_controller->remote_device[device_index] == NULL) { 73 /* This new device is now ready, so put it in the controller's 74 * remote device list so it is visible to CAM. 75 */ 76 isci_controller->remote_device[device_index] = 77 isci_remote_device; 78 79 if (isci_controller->has_been_scanned) { 80 /* The sim object has been scanned at least once 81 * already. In that case, create a CCB to instruct 82 * CAM to rescan this device. 83 * If the sim object has not been scanned, this device 84 * will get scanned as part of the initial scan. 85 */ 86 union ccb *ccb = xpt_alloc_ccb_nowait(); 87 88 xpt_create_path(&ccb->ccb_h.path, NULL, 89 cam_sim_path(isci_controller->sim), 90 isci_remote_device->index, CAM_LUN_WILDCARD); 91 92 xpt_rescan(ccb); 93 } 94 } 95 96 isci_remote_device_release_device_queue(isci_remote_device); 97 } 98 99 /** 100 * @brief This callback method informs the framework user that the remote 101 * device is not ready. Thus, it is incapable of processing IO 102 * requests. 103 * 104 * @param[in] controller This parameter specifies the controller object 105 * with which this callback is associated. 106 * @param[in] domain This parameter specifies the domain object with 107 * which this callback is associated. 108 * @param[in] remote_device This parameter specifies the device object with 109 * which this callback is associated. 110 * 111 * @return none 112 */ 113 void 114 scif_cb_remote_device_not_ready(SCI_CONTROLLER_HANDLE_T controller, 115 SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device) 116 { 117 118 } 119 120 /** 121 * @brief This callback method informs the framework user that the remote 122 * device failed. This typically occurs shortly after the device 123 * has been discovered, during the configuration phase for the device. 124 * 125 * @param[in] controller This parameter specifies the controller object 126 * with which this callback is associated. 127 * @param[in] domain This parameter specifies the domain object with 128 * which this callback is associated. 129 * @param[in] remote_device This parameter specifies the device object with 130 * which this callback is associated. 131 * @param[in] status This parameter specifies the specific failure condition 132 * associated with this device failure. 133 * 134 * @return none 135 */ 136 void 137 scif_cb_remote_device_failed(SCI_CONTROLLER_HANDLE_T controller, 138 SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device, 139 SCI_STATUS status) 140 { 141 142 } 143 144 void 145 isci_remote_device_reset(struct ISCI_REMOTE_DEVICE *remote_device, 146 union ccb *ccb) 147 { 148 struct ISCI_CONTROLLER *controller = remote_device->domain->controller; 149 struct ISCI_REQUEST *request; 150 struct ISCI_TASK_REQUEST *task_request; 151 SCI_STATUS status; 152 153 if (remote_device->is_resetting == TRUE) { 154 /* device is already being reset, so return immediately */ 155 return; 156 } 157 158 if (sci_pool_empty(controller->request_pool)) { 159 /* No requests are available in our request pool. If this reset is tied 160 * to a CCB, ask CAM to requeue it. Otherwise, we need to put it on our 161 * pending device reset list, so that the reset will occur when a request 162 * frees up. 163 */ 164 if (ccb == NULL) 165 sci_fast_list_insert_tail( 166 &controller->pending_device_reset_list, 167 &remote_device->pending_device_reset_element); 168 else { 169 ccb->ccb_h.status &= ~CAM_STATUS_MASK; 170 ccb->ccb_h.status |= CAM_REQUEUE_REQ; 171 xpt_done(ccb); 172 } 173 return; 174 } 175 176 isci_log_message(0, "ISCI", 177 "Sending reset to device on controller %d domain %d CAM index %d\n", 178 controller->index, remote_device->domain->index, 179 remote_device->index 180 ); 181 182 sci_pool_get(controller->request_pool, request); 183 task_request = (struct ISCI_TASK_REQUEST *)request; 184 185 task_request->parent.remote_device_handle = remote_device->sci_object; 186 task_request->ccb = ccb; 187 188 remote_device->is_resetting = TRUE; 189 190 status = (SCI_STATUS) scif_task_request_construct( 191 controller->scif_controller_handle, remote_device->sci_object, 192 SCI_CONTROLLER_INVALID_IO_TAG, (void *)task_request, 193 (void *)((char*)task_request + sizeof(struct ISCI_TASK_REQUEST)), 194 &task_request->sci_object); 195 196 if (status != SCI_SUCCESS) { 197 isci_task_request_complete(controller->scif_controller_handle, 198 remote_device->sci_object, task_request->sci_object, 199 (SCI_TASK_STATUS)status); 200 return; 201 } 202 203 status = (SCI_STATUS)scif_controller_start_task( 204 controller->scif_controller_handle, remote_device->sci_object, 205 task_request->sci_object, SCI_CONTROLLER_INVALID_IO_TAG); 206 207 if (status != SCI_SUCCESS) { 208 isci_task_request_complete( 209 controller->scif_controller_handle, 210 remote_device->sci_object, task_request->sci_object, 211 (SCI_TASK_STATUS)status); 212 return; 213 } 214 } 215 216 uint32_t 217 isci_remote_device_get_bitrate(struct ISCI_REMOTE_DEVICE *remote_device) 218 { 219 struct ISCI_DOMAIN *domain = remote_device->domain; 220 struct ISCI_CONTROLLER *controller = domain->controller; 221 SCI_PORT_HANDLE_T port_handle; 222 SCIC_PORT_PROPERTIES_T port_properties; 223 uint8_t phy_index; 224 SCI_PHY_HANDLE_T phy_handle; 225 SCIC_PHY_PROPERTIES_T phy_properties; 226 227 /* get a handle to the port associated with this remote device's 228 * domain 229 */ 230 port_handle = scif_domain_get_scic_port_handle(domain->sci_object); 231 scic_port_get_properties(port_handle, &port_properties); 232 233 /* get the lowest numbered phy in the port */ 234 phy_index = 0; 235 while ((port_properties.phy_mask != 0) && 236 !(port_properties.phy_mask & 0x1)) { 237 238 phy_index++; 239 port_properties.phy_mask >>= 1; 240 } 241 242 /* get the properties for the lowest numbered phy */ 243 scic_controller_get_phy_handle( 244 scif_controller_get_scic_handle(controller->scif_controller_handle), 245 phy_index, &phy_handle); 246 scic_phy_get_properties(phy_handle, &phy_properties); 247 248 switch (phy_properties.negotiated_link_rate) { 249 case SCI_SAS_150_GB: 250 return (150000); 251 case SCI_SAS_300_GB: 252 return (300000); 253 case SCI_SAS_600_GB: 254 return (600000); 255 default: 256 return (0); 257 } 258 } 259 260 void 261 isci_remote_device_freeze_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device, 262 lun_id_t lun) 263 { 264 if (!(remote_device->frozen_lun_mask & (1 << lun))) { 265 struct cam_path *path; 266 267 xpt_create_path(&path, NULL, 268 cam_sim_path(remote_device->domain->controller->sim), 269 remote_device->index, lun); 270 xpt_freeze_devq(path, 1); 271 xpt_free_path(path); 272 remote_device->frozen_lun_mask |= (1 << lun); 273 } 274 } 275 276 void 277 isci_remote_device_release_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device, 278 lun_id_t lun) 279 { 280 if (remote_device->frozen_lun_mask & (1 << lun)) { 281 struct cam_path *path; 282 283 remote_device->frozen_lun_mask &= ~(1 << lun); 284 xpt_create_path(&path, NULL, 285 cam_sim_path(remote_device->domain->controller->sim), 286 remote_device->index, lun); 287 xpt_release_devq(path, 1, TRUE); 288 xpt_free_path(path); 289 } 290 } 291 292 void 293 isci_remote_device_release_device_queue( 294 struct ISCI_REMOTE_DEVICE *device) 295 { 296 if (TAILQ_EMPTY(&device->queued_ccbs)) { 297 lun_id_t lun; 298 299 for (lun = 0; lun < ISCI_MAX_LUN; lun++) 300 isci_remote_device_release_lun_queue(device, lun); 301 } else { 302 /* 303 * We cannot unfreeze the devq, because there are still 304 * CCBs in our internal queue that need to be processed 305 * first. Mark this device, and the controller, so that 306 * the first CCB in this device's internal queue will be 307 * resubmitted after the current completion context 308 * unwinds. 309 */ 310 device->release_queued_ccb = TRUE; 311 device->domain->controller->release_queued_ccbs = TRUE; 312 313 isci_log_message(1, "ISCI", "schedule %p for release\n", 314 device); 315 } 316 } 317