1230557Sjimharris/*- 2230557Sjimharris * BSD LICENSE 3230557Sjimharris * 4230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 5230557Sjimharris * All rights reserved. 6230557Sjimharris * 7230557Sjimharris * Redistribution and use in source and binary forms, with or without 8230557Sjimharris * modification, are permitted provided that the following conditions 9230557Sjimharris * are met: 10230557Sjimharris * 11230557Sjimharris * * Redistributions of source code must retain the above copyright 12230557Sjimharris * notice, this list of conditions and the following disclaimer. 13230557Sjimharris * * Redistributions in binary form must reproduce the above copyright 14230557Sjimharris * notice, this list of conditions and the following disclaimer in 15230557Sjimharris * the documentation and/or other materials provided with the 16230557Sjimharris * distribution. 17230557Sjimharris * 18230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19230557Sjimharris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20230557Sjimharris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21230557Sjimharris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22230557Sjimharris * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23230557Sjimharris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24230557Sjimharris * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25230557Sjimharris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26230557Sjimharris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27230557Sjimharris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28230557Sjimharris * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29230557Sjimharris */ 30230557Sjimharris 31230557Sjimharris#include <sys/cdefs.h> 32230557Sjimharris__FBSDID("$FreeBSD$"); 33230557Sjimharris 34230557Sjimharris#include <dev/isci/isci.h> 35230557Sjimharris 36230557Sjimharris#include <cam/cam_periph.h> 37230557Sjimharris#include <cam/cam_xpt_periph.h> 38230557Sjimharris 39230557Sjimharris#include <dev/isci/scil/scif_task_request.h> 40230557Sjimharris#include <dev/isci/scil/scif_controller.h> 41230557Sjimharris#include <dev/isci/scil/scif_domain.h> 42230557Sjimharris#include <dev/isci/scil/scif_user_callback.h> 43230557Sjimharris 44230557Sjimharris#include <dev/isci/scil/scic_port.h> 45230557Sjimharris#include <dev/isci/scil/scic_phy.h> 46230557Sjimharris 47230557Sjimharris/** 48230557Sjimharris * @brief This callback method informs the framework user that the remote 49230557Sjimharris * device is ready and capable of processing IO requests. 50230557Sjimharris * 51230557Sjimharris * @param[in] controller This parameter specifies the controller object 52230557Sjimharris * with which this callback is associated. 53230557Sjimharris * @param[in] domain This parameter specifies the domain object with 54230557Sjimharris * which this callback is associated. 55230557Sjimharris * @param[in] remote_device This parameter specifies the device object with 56230557Sjimharris * which this callback is associated. 57230557Sjimharris * 58230557Sjimharris * @return none 59230557Sjimharris */ 60230557Sjimharrisvoid 61230557Sjimharrisscif_cb_remote_device_ready(SCI_CONTROLLER_HANDLE_T controller, 62230557Sjimharris SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device) 63230557Sjimharris{ 64230557Sjimharris struct ISCI_REMOTE_DEVICE *isci_remote_device = 65230557Sjimharris sci_object_get_association(remote_device); 66230557Sjimharris struct ISCI_CONTROLLER *isci_controller = 67230557Sjimharris sci_object_get_association(controller); 68230557Sjimharris uint32_t device_index = isci_remote_device->index; 69230557Sjimharris 70230557Sjimharris if (isci_controller->remote_device[device_index] == NULL) { 71230557Sjimharris /* This new device is now ready, so put it in the controller's 72230557Sjimharris * remote device list so it is visible to CAM. 73230557Sjimharris */ 74230557Sjimharris isci_controller->remote_device[device_index] = 75230557Sjimharris isci_remote_device; 76230557Sjimharris 77233371Sjimharris if (isci_controller->has_been_scanned) { 78233371Sjimharris /* The sim object has been scanned at least once 79233371Sjimharris * already. In that case, create a CCB to instruct 80233371Sjimharris * CAM to rescan this device. 81233371Sjimharris * If the sim object has not been scanned, this device 82233371Sjimharris * will get scanned as part of the initial scan. 83230557Sjimharris */ 84230557Sjimharris union ccb *ccb = xpt_alloc_ccb_nowait(); 85230557Sjimharris 86249468Smav xpt_create_path(&ccb->ccb_h.path, NULL, 87230557Sjimharris cam_sim_path(isci_controller->sim), 88230557Sjimharris isci_remote_device->index, CAM_LUN_WILDCARD); 89230557Sjimharris 90230557Sjimharris xpt_rescan(ccb); 91230557Sjimharris } 92230557Sjimharris } 93230557Sjimharris 94230557Sjimharris isci_remote_device_release_device_queue(isci_remote_device); 95230557Sjimharris} 96230557Sjimharris 97230557Sjimharris/** 98230557Sjimharris * @brief This callback method informs the framework user that the remote 99230557Sjimharris * device is not ready. Thus, it is incapable of processing IO 100230557Sjimharris * requests. 101230557Sjimharris * 102230557Sjimharris * @param[in] controller This parameter specifies the controller object 103230557Sjimharris * with which this callback is associated. 104230557Sjimharris * @param[in] domain This parameter specifies the domain object with 105230557Sjimharris * which this callback is associated. 106230557Sjimharris * @param[in] remote_device This parameter specifies the device object with 107230557Sjimharris * which this callback is associated. 108230557Sjimharris * 109230557Sjimharris * @return none 110230557Sjimharris */ 111230557Sjimharrisvoid 112230557Sjimharrisscif_cb_remote_device_not_ready(SCI_CONTROLLER_HANDLE_T controller, 113230557Sjimharris SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device) 114230557Sjimharris{ 115230557Sjimharris 116230557Sjimharris} 117230557Sjimharris 118230557Sjimharris/** 119230557Sjimharris * @brief This callback method informs the framework user that the remote 120230557Sjimharris * device failed. This typically occurs shortly after the device 121230557Sjimharris * has been discovered, during the configuration phase for the device. 122230557Sjimharris * 123230557Sjimharris * @param[in] controller This parameter specifies the controller object 124230557Sjimharris * with which this callback is associated. 125230557Sjimharris * @param[in] domain This parameter specifies the domain object with 126230557Sjimharris * which this callback is associated. 127230557Sjimharris * @param[in] remote_device This parameter specifies the device object with 128230557Sjimharris * which this callback is associated. 129230557Sjimharris * @param[in] status This parameter specifies the specific failure condition 130230557Sjimharris * associated with this device failure. 131230557Sjimharris * 132230557Sjimharris * @return none 133230557Sjimharris */ 134230557Sjimharrisvoid 135230557Sjimharrisscif_cb_remote_device_failed(SCI_CONTROLLER_HANDLE_T controller, 136230557Sjimharris SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device, 137230557Sjimharris SCI_STATUS status) 138230557Sjimharris{ 139230557Sjimharris 140230557Sjimharris} 141230557Sjimharris 142230557Sjimharrisvoid 143230557Sjimharrisisci_remote_device_reset(struct ISCI_REMOTE_DEVICE *remote_device, 144230557Sjimharris union ccb *ccb) 145230557Sjimharris{ 146230557Sjimharris struct ISCI_CONTROLLER *controller = remote_device->domain->controller; 147230557Sjimharris struct ISCI_REQUEST *request; 148230557Sjimharris struct ISCI_TASK_REQUEST *task_request; 149230557Sjimharris SCI_STATUS status; 150230557Sjimharris 151230557Sjimharris if (remote_device->is_resetting == TRUE) { 152230557Sjimharris /* device is already being reset, so return immediately */ 153230557Sjimharris return; 154230557Sjimharris } 155230557Sjimharris 156230557Sjimharris if (sci_pool_empty(controller->request_pool)) { 157230557Sjimharris /* No requests are available in our request pool. If this reset is tied 158230557Sjimharris * to a CCB, ask CAM to requeue it. Otherwise, we need to put it on our 159230557Sjimharris * pending device reset list, so that the reset will occur when a request 160230557Sjimharris * frees up. 161230557Sjimharris */ 162230557Sjimharris if (ccb == NULL) 163230557Sjimharris sci_fast_list_insert_tail( 164230557Sjimharris &controller->pending_device_reset_list, 165230557Sjimharris &remote_device->pending_device_reset_element); 166230557Sjimharris else { 167230557Sjimharris ccb->ccb_h.status &= ~CAM_STATUS_MASK; 168230557Sjimharris ccb->ccb_h.status |= CAM_REQUEUE_REQ; 169230557Sjimharris xpt_done(ccb); 170230557Sjimharris } 171230557Sjimharris return; 172230557Sjimharris } 173230557Sjimharris 174230557Sjimharris isci_log_message(0, "ISCI", 175230557Sjimharris "Sending reset to device on controller %d domain %d CAM index %d\n", 176230557Sjimharris controller->index, remote_device->domain->index, 177230557Sjimharris remote_device->index 178230557Sjimharris ); 179230557Sjimharris 180230557Sjimharris sci_pool_get(controller->request_pool, request); 181230557Sjimharris task_request = (struct ISCI_TASK_REQUEST *)request; 182230557Sjimharris 183230557Sjimharris task_request->parent.remote_device_handle = remote_device->sci_object; 184230557Sjimharris task_request->ccb = ccb; 185230557Sjimharris 186230557Sjimharris remote_device->is_resetting = TRUE; 187230557Sjimharris 188230557Sjimharris status = (SCI_STATUS) scif_task_request_construct( 189230557Sjimharris controller->scif_controller_handle, remote_device->sci_object, 190230557Sjimharris SCI_CONTROLLER_INVALID_IO_TAG, (void *)task_request, 191230557Sjimharris (void *)((char*)task_request + sizeof(struct ISCI_TASK_REQUEST)), 192230557Sjimharris &task_request->sci_object); 193230557Sjimharris 194230557Sjimharris if (status != SCI_SUCCESS) { 195230557Sjimharris isci_task_request_complete(controller->scif_controller_handle, 196230557Sjimharris remote_device->sci_object, task_request->sci_object, 197231296Sjimharris (SCI_TASK_STATUS)status); 198230557Sjimharris return; 199230557Sjimharris } 200230557Sjimharris 201230557Sjimharris status = (SCI_STATUS)scif_controller_start_task( 202230557Sjimharris controller->scif_controller_handle, remote_device->sci_object, 203230557Sjimharris task_request->sci_object, SCI_CONTROLLER_INVALID_IO_TAG); 204230557Sjimharris 205230557Sjimharris if (status != SCI_SUCCESS) { 206230557Sjimharris isci_task_request_complete( 207230557Sjimharris controller->scif_controller_handle, 208230557Sjimharris remote_device->sci_object, task_request->sci_object, 209231296Sjimharris (SCI_TASK_STATUS)status); 210230557Sjimharris return; 211230557Sjimharris } 212230557Sjimharris} 213230557Sjimharris 214230557Sjimharrisuint32_t 215230557Sjimharrisisci_remote_device_get_bitrate(struct ISCI_REMOTE_DEVICE *remote_device) 216230557Sjimharris{ 217230557Sjimharris struct ISCI_DOMAIN *domain = remote_device->domain; 218230557Sjimharris struct ISCI_CONTROLLER *controller = domain->controller; 219230557Sjimharris SCI_PORT_HANDLE_T port_handle; 220230557Sjimharris SCIC_PORT_PROPERTIES_T port_properties; 221230557Sjimharris uint8_t phy_index; 222230557Sjimharris SCI_PHY_HANDLE_T phy_handle; 223230557Sjimharris SCIC_PHY_PROPERTIES_T phy_properties; 224230557Sjimharris 225230557Sjimharris /* get a handle to the port associated with this remote device's 226230557Sjimharris * domain 227230557Sjimharris */ 228230557Sjimharris port_handle = scif_domain_get_scic_port_handle(domain->sci_object); 229230557Sjimharris scic_port_get_properties(port_handle, &port_properties); 230230557Sjimharris 231230557Sjimharris /* get the lowest numbered phy in the port */ 232230557Sjimharris phy_index = 0; 233230557Sjimharris while ((port_properties.phy_mask != 0) && 234230557Sjimharris !(port_properties.phy_mask & 0x1)) { 235230557Sjimharris 236230557Sjimharris phy_index++; 237230557Sjimharris port_properties.phy_mask >>= 1; 238230557Sjimharris } 239230557Sjimharris 240230557Sjimharris /* get the properties for the lowest numbered phy */ 241230557Sjimharris scic_controller_get_phy_handle( 242230557Sjimharris scif_controller_get_scic_handle(controller->scif_controller_handle), 243230557Sjimharris phy_index, &phy_handle); 244230557Sjimharris scic_phy_get_properties(phy_handle, &phy_properties); 245230557Sjimharris 246230557Sjimharris switch (phy_properties.negotiated_link_rate) { 247230557Sjimharris case SCI_SAS_150_GB: 248230557Sjimharris return (150000); 249230557Sjimharris case SCI_SAS_300_GB: 250230557Sjimharris return (300000); 251230557Sjimharris case SCI_SAS_600_GB: 252230557Sjimharris return (600000); 253230557Sjimharris default: 254230557Sjimharris return (0); 255230557Sjimharris } 256230557Sjimharris} 257230557Sjimharris 258230557Sjimharrisvoid 259230557Sjimharrisisci_remote_device_freeze_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device, 260230557Sjimharris lun_id_t lun) 261230557Sjimharris{ 262230557Sjimharris if (!(remote_device->frozen_lun_mask & (1 << lun))) { 263230557Sjimharris struct cam_path *path; 264230557Sjimharris 265249468Smav xpt_create_path(&path, NULL, 266230557Sjimharris cam_sim_path(remote_device->domain->controller->sim), 267230557Sjimharris remote_device->index, lun); 268230557Sjimharris xpt_freeze_devq(path, 1); 269230557Sjimharris xpt_free_path(path); 270230557Sjimharris remote_device->frozen_lun_mask |= (1 << lun); 271230557Sjimharris } 272230557Sjimharris} 273230557Sjimharris 274230557Sjimharrisvoid 275230557Sjimharrisisci_remote_device_release_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device, 276230557Sjimharris lun_id_t lun) 277230557Sjimharris{ 278230557Sjimharris if (remote_device->frozen_lun_mask & (1 << lun)) { 279230557Sjimharris struct cam_path *path; 280230557Sjimharris 281239665Sjimharris remote_device->frozen_lun_mask &= ~(1 << lun); 282249468Smav xpt_create_path(&path, NULL, 283230557Sjimharris cam_sim_path(remote_device->domain->controller->sim), 284230557Sjimharris remote_device->index, lun); 285230557Sjimharris xpt_release_devq(path, 1, TRUE); 286230557Sjimharris xpt_free_path(path); 287230557Sjimharris } 288230557Sjimharris} 289230557Sjimharris 290230557Sjimharrisvoid 291230557Sjimharrisisci_remote_device_release_device_queue( 292234106Sjimharris struct ISCI_REMOTE_DEVICE *device) 293230557Sjimharris{ 294234106Sjimharris if (TAILQ_EMPTY(&device->queued_ccbs)) { 295234106Sjimharris lun_id_t lun; 296234106Sjimharris 297234106Sjimharris for (lun = 0; lun < ISCI_MAX_LUN; lun++) 298234106Sjimharris isci_remote_device_release_lun_queue(device, lun); 299234106Sjimharris } else { 300235751Sjimharris /* 301235751Sjimharris * We cannot unfreeze the devq, because there are still 302235751Sjimharris * CCBs in our internal queue that need to be processed 303235751Sjimharris * first. Mark this device, and the controller, so that 304235751Sjimharris * the first CCB in this device's internal queue will be 305235751Sjimharris * resubmitted after the current completion context 306235751Sjimharris * unwinds. 307235751Sjimharris */ 308235751Sjimharris device->release_queued_ccb = TRUE; 309235751Sjimharris device->domain->controller->release_queued_ccbs = TRUE; 310234106Sjimharris 311235751Sjimharris isci_log_message(1, "ISCI", "schedule %p for release\n", 312235751Sjimharris device); 313234106Sjimharris } 314230557Sjimharris} 315