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->sim != NULL) { 78 /* The sim object is not NULL, meaning we have attached 79 * the controller to CAM already. In that case, create 80 * a CCB to instruct CAM to rescan this device. 81 * If the sim object is NULL, this device will get 82 * scanned as part of the initial scan when the 83 * controller is attached to CAM. 84 */ 85 union ccb *ccb = xpt_alloc_ccb_nowait(); 86 87 xpt_create_path(&ccb->ccb_h.path, xpt_periph, 88 cam_sim_path(isci_controller->sim), 89 isci_remote_device->index, CAM_LUN_WILDCARD); 90 91 xpt_rescan(ccb); 92 } 93 } 94 95 isci_remote_device_release_device_queue(isci_remote_device); 96 } 97 98 /** 99 * @brief This callback method informs the framework user that the remote 100 * device is not ready. Thus, it is incapable of processing IO 101 * requests. 102 * 103 * @param[in] controller This parameter specifies the controller object 104 * with which this callback is associated. 105 * @param[in] domain This parameter specifies the domain object with 106 * which this callback is associated. 107 * @param[in] remote_device This parameter specifies the device object with 108 * which this callback is associated. 109 * 110 * @return none 111 */ 112 void 113 scif_cb_remote_device_not_ready(SCI_CONTROLLER_HANDLE_T controller, 114 SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device) 115 { 116 117 } 118 119 /** 120 * @brief This callback method informs the framework user that the remote 121 * device failed. This typically occurs shortly after the device 122 * has been discovered, during the configuration phase for the device. 123 * 124 * @param[in] controller This parameter specifies the controller object 125 * with which this callback is associated. 126 * @param[in] domain This parameter specifies the domain object with 127 * which this callback is associated. 128 * @param[in] remote_device This parameter specifies the device object with 129 * which this callback is associated. 130 * @param[in] status This parameter specifies the specific failure condition 131 * associated with this device failure. 132 * 133 * @return none 134 */ 135 void 136 scif_cb_remote_device_failed(SCI_CONTROLLER_HANDLE_T controller, 137 SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device, 138 SCI_STATUS status) 139 { 140 141 } 142 143 void 144 isci_remote_device_reset(struct ISCI_REMOTE_DEVICE *remote_device, 145 union ccb *ccb) 146 { 147 struct ISCI_CONTROLLER *controller = remote_device->domain->controller; 148 struct ISCI_REQUEST *request; 149 struct ISCI_TASK_REQUEST *task_request; 150 SCI_STATUS status; 151 152 if (remote_device->is_resetting == TRUE) { 153 /* device is already being reset, so return immediately */ 154 return; 155 } 156 157 if (sci_pool_empty(controller->request_pool)) { 158 /* No requests are available in our request pool. If this reset is tied 159 * to a CCB, ask CAM to requeue it. Otherwise, we need to put it on our 160 * pending device reset list, so that the reset will occur when a request 161 * frees up. 162 */ 163 if (ccb == NULL) 164 sci_fast_list_insert_tail( 165 &controller->pending_device_reset_list, 166 &remote_device->pending_device_reset_element); 167 else { 168 ccb->ccb_h.status &= ~CAM_STATUS_MASK; 169 ccb->ccb_h.status |= CAM_REQUEUE_REQ; 170 xpt_done(ccb); 171 } 172 return; 173 } 174 175 isci_log_message(0, "ISCI", 176 "Sending reset to device on controller %d domain %d CAM index %d\n", 177 controller->index, remote_device->domain->index, 178 remote_device->index 179 ); 180 181 sci_pool_get(controller->request_pool, request); 182 task_request = (struct ISCI_TASK_REQUEST *)request; 183 184 task_request->parent.remote_device_handle = remote_device->sci_object; 185 task_request->ccb = ccb; 186 187 remote_device->is_resetting = TRUE; 188 189 status = (SCI_STATUS) scif_task_request_construct( 190 controller->scif_controller_handle, remote_device->sci_object, 191 SCI_CONTROLLER_INVALID_IO_TAG, (void *)task_request, 192 (void *)((char*)task_request + sizeof(struct ISCI_TASK_REQUEST)), 193 &task_request->sci_object); 194 195 if (status != SCI_SUCCESS) { 196 isci_task_request_complete(controller->scif_controller_handle, 197 remote_device->sci_object, task_request->sci_object, 198 status); 199 return; 200 } 201 202 status = (SCI_STATUS)scif_controller_start_task( 203 controller->scif_controller_handle, remote_device->sci_object, 204 task_request->sci_object, SCI_CONTROLLER_INVALID_IO_TAG); 205 206 if (status != SCI_SUCCESS) { 207 isci_task_request_complete( 208 controller->scif_controller_handle, 209 remote_device->sci_object, task_request->sci_object, 210 status); 211 return; 212 } 213 } 214 215 uint32_t 216 isci_remote_device_get_bitrate(struct ISCI_REMOTE_DEVICE *remote_device) 217 { 218 struct ISCI_DOMAIN *domain = remote_device->domain; 219 struct ISCI_CONTROLLER *controller = domain->controller; 220 SCI_PORT_HANDLE_T port_handle; 221 SCIC_PORT_PROPERTIES_T port_properties; 222 uint8_t phy_index; 223 SCI_PHY_HANDLE_T phy_handle; 224 SCIC_PHY_PROPERTIES_T phy_properties; 225 226 /* get a handle to the port associated with this remote device's 227 * domain 228 */ 229 port_handle = scif_domain_get_scic_port_handle(domain->sci_object); 230 scic_port_get_properties(port_handle, &port_properties); 231 232 /* get the lowest numbered phy in the port */ 233 phy_index = 0; 234 while ((port_properties.phy_mask != 0) && 235 !(port_properties.phy_mask & 0x1)) { 236 237 phy_index++; 238 port_properties.phy_mask >>= 1; 239 } 240 241 /* get the properties for the lowest numbered phy */ 242 scic_controller_get_phy_handle( 243 scif_controller_get_scic_handle(controller->scif_controller_handle), 244 phy_index, &phy_handle); 245 scic_phy_get_properties(phy_handle, &phy_properties); 246 247 switch (phy_properties.negotiated_link_rate) { 248 case SCI_SAS_150_GB: 249 return (150000); 250 case SCI_SAS_300_GB: 251 return (300000); 252 case SCI_SAS_600_GB: 253 return (600000); 254 default: 255 return (0); 256 } 257 } 258 259 void 260 isci_remote_device_freeze_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device, 261 lun_id_t lun) 262 { 263 if (!(remote_device->frozen_lun_mask & (1 << lun))) { 264 struct cam_path *path; 265 266 xpt_create_path(&path, xpt_periph, 267 cam_sim_path(remote_device->domain->controller->sim), 268 remote_device->index, lun); 269 xpt_freeze_devq(path, 1); 270 xpt_free_path(path); 271 remote_device->frozen_lun_mask |= (1 << lun); 272 } 273 } 274 275 void 276 isci_remote_device_release_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device, 277 lun_id_t lun) 278 { 279 if (remote_device->frozen_lun_mask & (1 << lun)) { 280 struct cam_path *path; 281 282 xpt_create_path(&path, xpt_periph, 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 remote_device->frozen_lun_mask &= ~(1 << lun); 288 } 289 } 290 291 void 292 isci_remote_device_release_device_queue( 293 struct ISCI_REMOTE_DEVICE *remote_device) 294 { 295 lun_id_t lun; 296 for (lun = 0; lun < ISCI_MAX_LUN; lun++) 297 isci_remote_device_release_lun_queue(remote_device, lun); 298 } 299