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