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_domain.h> 40 #include <dev/isci/scil/scif_remote_device.h> 41 #include <dev/isci/scil/scif_controller.h> 42 #include <dev/isci/scil/scif_user_callback.h> 43 44 /** 45 * @brief This callback method informs the framework user that something 46 * in the supplied domain has changed (e.g. a device was added or 47 * removed). 48 * 49 * This callback is called by the framework outside of discovery or 50 * target reset processes. Specifically, domain changes occurring 51 * during these processes are handled by the framework. For example, 52 * in the case of Serial Attached SCSI, reception of a BROADCAST (CHANGE) 53 * during discovery will cause discovery to restart. Thus, discovery 54 * does not complete until all BCNs are processed. Note, during controller 55 * stopping/reset process, the framework user should not expect this call 56 * back. 57 * 58 * @param[in] controller This parameter specifies the controller object 59 * with which this callback is associated. 60 * @param[in] domain This parameter specifies the domain object with 61 * which this callback is associated. 62 * 63 * @return none 64 */ 65 void 66 scif_cb_domain_change_notification(SCI_CONTROLLER_HANDLE_T controller, 67 SCI_DOMAIN_HANDLE_T domain) 68 { 69 struct ISCI_CONTROLLER *isci_controller = 70 (struct ISCI_CONTROLLER *)sci_object_get_association(controller); 71 72 /* When the controller start is complete, we will explicitly discover 73 * all of the domains then. This is because SCIF will not allow 74 * any I/O to start until the controller is ready, meaning internal SMP 75 * requests triggered by domain discovery won't work until the controller 76 * is ready. 77 */ 78 if (isci_controller->is_started == TRUE) 79 scif_domain_discover(domain, 80 scif_domain_get_suggested_discover_timeout(domain), 81 DEVICE_TIMEOUT); 82 } 83 84 /** 85 * @brief This callback method informs the framework user that a previously 86 * requested discovery operation on the domain has completed. 87 * 88 * @param[in] controller This parameter specifies the controller object 89 * with which this callback is associated. 90 * @param[in] domain This parameter specifies the domain object with 91 * which this callback is associated. 92 * @param[in] completion_status This parameter indicates the results of the 93 * discovery operation. 94 * 95 * @return none 96 */ 97 void 98 scif_cb_domain_discovery_complete(SCI_CONTROLLER_HANDLE_T controller, 99 SCI_DOMAIN_HANDLE_T domain, SCI_STATUS completion_status) 100 { 101 102 if(completion_status != SCI_SUCCESS) 103 isci_log_message(0, "ISCI", 104 "scif_cb_domain_discovery_complete status = 0x%x\n", 105 completion_status); 106 107 isci_controller_domain_discovery_complete( 108 (struct ISCI_CONTROLLER *)sci_object_get_association(controller), 109 (struct ISCI_DOMAIN *) sci_object_get_association(domain)); 110 } 111 112 /** 113 * @brief This callback method informs the framework user that a previously 114 * requested reset operation on the domain has completed. 115 * 116 * @param[in] controller This parameter specifies the controller object 117 * with which this callback is associated. 118 * @param[in] domain This parameter specifies the domain object with 119 * which this callback is associated. 120 * @param[in] completion_status This parameter indicates the results of the 121 * reset operation. 122 * 123 * @return none 124 */ 125 void 126 scif_cb_domain_reset_complete(SCI_CONTROLLER_HANDLE_T controller, 127 SCI_DOMAIN_HANDLE_T domain, SCI_STATUS completion_status) 128 { 129 130 } 131 132 /** 133 * @brief This callback method informs the framework user that the domain 134 * is ready and capable of processing IO requests for devices found 135 * inside it. 136 * 137 * @param[in] controller This parameter specifies the controller object 138 * with which this callback is associated. 139 * @param[in] domain This parameter specifies the domain object with 140 * which this callback is associated. 141 * 142 * @return none 143 */ 144 void 145 scif_cb_domain_ready(SCI_CONTROLLER_HANDLE_T controller, 146 SCI_DOMAIN_HANDLE_T domain) 147 { 148 uint32_t i; 149 struct ISCI_DOMAIN *isci_domain = sci_object_get_association(domain); 150 struct ISCI_CONTROLLER *isci_controller = 151 sci_object_get_association(controller); 152 153 for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) { 154 struct ISCI_REMOTE_DEVICE *remote_device = 155 isci_controller->remote_device[i]; 156 157 if (remote_device != NULL && 158 remote_device->domain == isci_domain) 159 isci_remote_device_release_device_queue(remote_device); 160 } 161 } 162 163 /** 164 * @brief This callback method informs the framework user that the domain 165 * is no longer ready. Thus, it is incapable of processing IO 166 * requests for devices found inside it. 167 * 168 * @param[in] controller This parameter specifies the controller object 169 * with which this callback is associated. 170 * @param[in] domain This parameter specifies the domain object with 171 * which this callback is associated. 172 * 173 * @return none 174 */ 175 void 176 scif_cb_domain_not_ready(SCI_CONTROLLER_HANDLE_T controller, 177 SCI_DOMAIN_HANDLE_T domain) 178 { 179 180 } 181 182 /** 183 * @brief This callback method informs the framework user that a new 184 * direct attached device was found in the domain. 185 * 186 * @param[in] controller This parameter specifies the controller object 187 * with which this callback is associated. 188 * @param[in] domain This parameter specifies the domain object with 189 * which this callback is associated. 190 * @param[in] sas_address This parameter specifies the SAS address of 191 * the new device. 192 * @param[in] protocols This parameter specifies the protocols 193 * supported by the newly discovered device. 194 * 195 * @return none 196 */ 197 void 198 scif_cb_domain_da_device_added(SCI_CONTROLLER_HANDLE_T controller, 199 SCI_DOMAIN_HANDLE_T domain, SCI_SAS_ADDRESS_T *sas_address, 200 SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T *protocols) 201 { 202 struct ISCI_REMOTE_DEVICE *remote_device; 203 struct ISCI_DOMAIN *isci_domain = 204 (struct ISCI_DOMAIN *)sci_object_get_association(domain); 205 206 /* 207 * For direct-attached devices, do not pull the device object from 208 * the pool. Rather, use the one stored in the domain object which 209 * will ensure that we always get consistent target ids for direct 210 * attached devices. 211 */ 212 remote_device = isci_domain->da_remote_device; 213 214 scif_remote_device_construct(domain, 215 (uint8_t*)remote_device + sizeof(struct ISCI_REMOTE_DEVICE), 216 &(remote_device->sci_object)); 217 218 sci_object_set_association(remote_device->sci_object, remote_device); 219 220 scif_remote_device_da_construct(remote_device->sci_object, sas_address, 221 protocols); 222 223 /* We do not put the device in the ISCI_CONTROLLER's device array yet. 224 * That will happen once the device becomes ready (see 225 * scif_cb_remote_device_ready). 226 */ 227 228 remote_device->domain = isci_domain; 229 } 230 231 /** 232 * @brief This callback method informs the framework user that a new 233 * expander attached device was found in the domain. 234 * 235 * @param[in] controller This parameter specifies the controller object 236 * with which this callback is associated. 237 * @param[in] domain This parameter specifies the domain object with 238 * which this callback is associated. 239 * @param[in] containing_device This parameter specifies the remote 240 * device that contains the device that was added. 241 * @param[in] smp_response This parameter specifies the SMP response 242 * data associated with the newly discovered device. 243 * 244 * @return none 245 */ 246 void 247 scif_cb_domain_ea_device_added(SCI_CONTROLLER_HANDLE_T controller, 248 SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T containing_device, 249 SMP_RESPONSE_DISCOVER_T *smp_response) 250 { 251 struct ISCI_REMOTE_DEVICE *remote_device; 252 struct ISCI_DOMAIN *isci_domain = 253 (struct ISCI_DOMAIN *)sci_object_get_association(domain); 254 struct ISCI_CONTROLLER *isci_controller = 255 (struct ISCI_CONTROLLER *)sci_object_get_association(controller); 256 257 sci_pool_get(isci_controller->remote_device_pool, remote_device); 258 259 scif_remote_device_construct( domain, 260 (uint8_t*)remote_device + sizeof(struct ISCI_REMOTE_DEVICE), 261 &(remote_device->sci_object)); 262 263 sci_object_set_association(remote_device->sci_object, remote_device); 264 265 scif_remote_device_ea_construct(remote_device->sci_object, 266 containing_device, smp_response); 267 268 /* We do not put the device in the ISCI_CONTROLLER's device array yet. 269 * That will happen once the device becomes ready (see 270 * scif_cb_remote_device_ready). 271 */ 272 remote_device->domain = isci_domain; 273 } 274 275 /** 276 * @brief This callback method informs the framework user that a device 277 * has been removed from the domain. 278 * 279 * @param[in] controller This parameter specifies the controller object 280 * with which this callback is associated. 281 * @param[in] domain This parameter specifies the domain object with 282 * which this callback is associated. 283 * @param[in] remote_device This parameter specifies the device object with 284 * which this callback is associated. 285 * 286 * @return none 287 */ 288 void 289 scif_cb_domain_device_removed(SCI_CONTROLLER_HANDLE_T controller, 290 SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device) 291 { 292 struct ISCI_REMOTE_DEVICE *isci_remote_device = 293 (struct ISCI_REMOTE_DEVICE *)sci_object_get_association(remote_device); 294 struct ISCI_DOMAIN *isci_domain = 295 (struct ISCI_DOMAIN *)sci_object_get_association(domain); 296 struct ISCI_CONTROLLER *isci_controller = 297 (struct ISCI_CONTROLLER *)sci_object_get_association(controller); 298 uint32_t path = cam_sim_path(isci_controller->sim); 299 union ccb *ccb = xpt_alloc_ccb_nowait(); 300 301 isci_controller->remote_device[isci_remote_device->index] = NULL; 302 303 xpt_create_path(&ccb->ccb_h.path, NULL, path, 304 isci_remote_device->index, CAM_LUN_WILDCARD); 305 306 xpt_rescan(ccb); 307 308 scif_remote_device_destruct(remote_device); 309 310 /* 311 * Only put the remote device back into the pool if it was an 312 * expander-attached device. 313 */ 314 if (isci_remote_device != isci_domain->da_remote_device) 315 sci_pool_put(isci_controller->remote_device_pool, 316 isci_remote_device); 317 } 318 319 void 320 isci_domain_construct(struct ISCI_DOMAIN *domain, uint32_t domain_index, 321 struct ISCI_CONTROLLER *controller) 322 { 323 324 scif_controller_get_domain_handle( controller->scif_controller_handle, 325 domain_index, &domain->sci_object); 326 327 domain->index = domain_index; 328 domain->controller = controller; 329 sci_object_set_association(domain->sci_object, (void *)domain); 330 } 331