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