16f231ddaSDan Williams /* 26f231ddaSDan Williams * This file is provided under a dual BSD/GPLv2 license. When using or 36f231ddaSDan Williams * redistributing this file, you may do so under either license. 46f231ddaSDan Williams * 56f231ddaSDan Williams * GPL LICENSE SUMMARY 66f231ddaSDan Williams * 76f231ddaSDan Williams * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 86f231ddaSDan Williams * 96f231ddaSDan Williams * This program is free software; you can redistribute it and/or modify 106f231ddaSDan Williams * it under the terms of version 2 of the GNU General Public License as 116f231ddaSDan Williams * published by the Free Software Foundation. 126f231ddaSDan Williams * 136f231ddaSDan Williams * This program is distributed in the hope that it will be useful, but 146f231ddaSDan Williams * WITHOUT ANY WARRANTY; without even the implied warranty of 156f231ddaSDan Williams * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 166f231ddaSDan Williams * General Public License for more details. 176f231ddaSDan Williams * 186f231ddaSDan Williams * You should have received a copy of the GNU General Public License 196f231ddaSDan Williams * along with this program; if not, write to the Free Software 206f231ddaSDan Williams * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 216f231ddaSDan Williams * The full GNU General Public License is included in this distribution 226f231ddaSDan Williams * in the file called LICENSE.GPL. 236f231ddaSDan Williams * 246f231ddaSDan Williams * BSD LICENSE 256f231ddaSDan Williams * 266f231ddaSDan Williams * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 276f231ddaSDan Williams * All rights reserved. 286f231ddaSDan Williams * 296f231ddaSDan Williams * Redistribution and use in source and binary forms, with or without 306f231ddaSDan Williams * modification, are permitted provided that the following conditions 316f231ddaSDan Williams * are met: 326f231ddaSDan Williams * 336f231ddaSDan Williams * * Redistributions of source code must retain the above copyright 346f231ddaSDan Williams * notice, this list of conditions and the following disclaimer. 356f231ddaSDan Williams * * Redistributions in binary form must reproduce the above copyright 366f231ddaSDan Williams * notice, this list of conditions and the following disclaimer in 376f231ddaSDan Williams * the documentation and/or other materials provided with the 386f231ddaSDan Williams * distribution. 396f231ddaSDan Williams * * Neither the name of Intel Corporation nor the names of its 406f231ddaSDan Williams * contributors may be used to endorse or promote products derived 416f231ddaSDan Williams * from this software without specific prior written permission. 426f231ddaSDan Williams * 436f231ddaSDan Williams * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 446f231ddaSDan Williams * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 456f231ddaSDan Williams * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 466f231ddaSDan Williams * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 476f231ddaSDan Williams * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 486f231ddaSDan Williams * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 496f231ddaSDan Williams * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 506f231ddaSDan Williams * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 516f231ddaSDan Williams * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 526f231ddaSDan Williams * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 536f231ddaSDan Williams * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 546f231ddaSDan Williams */ 556f231ddaSDan Williams 566f231ddaSDan Williams #include "isci.h" 576f231ddaSDan Williams #include "scic_io_request.h" 586f231ddaSDan Williams #include "scic_remote_device.h" 596f231ddaSDan Williams #include "scic_port.h" 606f231ddaSDan Williams 616f231ddaSDan Williams #include "port.h" 626f231ddaSDan Williams #include "request.h" 636f231ddaSDan Williams #include "host.h" 64d044af17SDan Williams #include "probe_roms.h" 65ca841f0eSChristoph Hellwig #include "core/scic_sds_controller.h" 666f231ddaSDan Williams 67c7ef4031SDan Williams irqreturn_t isci_msix_isr(int vec, void *data) 686f231ddaSDan Williams { 69c7ef4031SDan Williams struct isci_host *ihost = data; 70c7ef4031SDan Williams struct scic_sds_controller *scic = ihost->core_controller; 716f231ddaSDan Williams 720cf89d1dSDan Williams if (scic_sds_controller_isr(scic)) 73c7ef4031SDan Williams tasklet_schedule(&ihost->completion_tasklet); 746f231ddaSDan Williams 75c7ef4031SDan Williams return IRQ_HANDLED; 76c7ef4031SDan Williams } 77c7ef4031SDan Williams 78c7ef4031SDan Williams irqreturn_t isci_intx_isr(int vec, void *data) 796f231ddaSDan Williams { 806f231ddaSDan Williams irqreturn_t ret = IRQ_NONE; 8131e824edSDan Williams struct isci_host *ihost = data; 82c7ef4031SDan Williams struct scic_sds_controller *scic = ihost->core_controller; 836f231ddaSDan Williams 84c7ef4031SDan Williams if (scic_sds_controller_isr(scic)) { 8531e824edSDan Williams writel(SMU_ISR_COMPLETION, &scic->smu_registers->interrupt_status); 86c7ef4031SDan Williams tasklet_schedule(&ihost->completion_tasklet); 876f231ddaSDan Williams ret = IRQ_HANDLED; 8892f4f0f5SDan Williams } else if (scic_sds_controller_error_isr(scic)) { 8992f4f0f5SDan Williams spin_lock(&ihost->scic_lock); 9092f4f0f5SDan Williams scic_sds_controller_error_handler(scic); 9192f4f0f5SDan Williams spin_unlock(&ihost->scic_lock); 9292f4f0f5SDan Williams ret = IRQ_HANDLED; 936f231ddaSDan Williams } 9492f4f0f5SDan Williams 956f231ddaSDan Williams return ret; 966f231ddaSDan Williams } 976f231ddaSDan Williams 9892f4f0f5SDan Williams irqreturn_t isci_error_isr(int vec, void *data) 9992f4f0f5SDan Williams { 10092f4f0f5SDan Williams struct isci_host *ihost = data; 10192f4f0f5SDan Williams struct scic_sds_controller *scic = ihost->core_controller; 10292f4f0f5SDan Williams 10392f4f0f5SDan Williams if (scic_sds_controller_error_isr(scic)) 10492f4f0f5SDan Williams scic_sds_controller_error_handler(scic); 10592f4f0f5SDan Williams 10692f4f0f5SDan Williams return IRQ_HANDLED; 10792f4f0f5SDan Williams } 1086f231ddaSDan Williams 1096f231ddaSDan Williams /** 1106f231ddaSDan Williams * isci_host_start_complete() - This function is called by the core library, 1116f231ddaSDan Williams * through the ISCI Module, to indicate controller start status. 1126f231ddaSDan Williams * @isci_host: This parameter specifies the ISCI host object 1136f231ddaSDan Williams * @completion_status: This parameter specifies the completion status from the 1146f231ddaSDan Williams * core library. 1156f231ddaSDan Williams * 1166f231ddaSDan Williams */ 1170cf89d1dSDan Williams void isci_host_start_complete(struct isci_host *ihost, enum sci_status completion_status) 1186f231ddaSDan Williams { 1190cf89d1dSDan Williams if (completion_status != SCI_SUCCESS) 1200cf89d1dSDan Williams dev_info(&ihost->pdev->dev, 1210cf89d1dSDan Williams "controller start timed out, continuing...\n"); 1220cf89d1dSDan Williams isci_host_change_state(ihost, isci_ready); 1230cf89d1dSDan Williams clear_bit(IHOST_START_PENDING, &ihost->flags); 1240cf89d1dSDan Williams wake_up(&ihost->eventq); 1256f231ddaSDan Williams } 1266f231ddaSDan Williams 127c7ef4031SDan Williams int isci_host_scan_finished(struct Scsi_Host *shost, unsigned long time) 1286f231ddaSDan Williams { 1294393aa4eSDan Williams struct isci_host *ihost = SHOST_TO_SAS_HA(shost)->lldd_ha; 1306f231ddaSDan Williams 13177950f51SEdmund Nadolski if (test_bit(IHOST_START_PENDING, &ihost->flags)) 1326f231ddaSDan Williams return 0; 1336f231ddaSDan Williams 13477950f51SEdmund Nadolski /* todo: use sas_flush_discovery once it is upstream */ 13577950f51SEdmund Nadolski scsi_flush_work(shost); 13677950f51SEdmund Nadolski 13777950f51SEdmund Nadolski scsi_flush_work(shost); 1386f231ddaSDan Williams 1390cf89d1dSDan Williams dev_dbg(&ihost->pdev->dev, 1400cf89d1dSDan Williams "%s: ihost->status = %d, time = %ld\n", 1410cf89d1dSDan Williams __func__, isci_host_get_state(ihost), time); 1426f231ddaSDan Williams 1436f231ddaSDan Williams return 1; 1446f231ddaSDan Williams 1456f231ddaSDan Williams } 1466f231ddaSDan Williams 1476f231ddaSDan Williams void isci_host_scan_start(struct Scsi_Host *shost) 1486f231ddaSDan Williams { 1494393aa4eSDan Williams struct isci_host *ihost = SHOST_TO_SAS_HA(shost)->lldd_ha; 1500cf89d1dSDan Williams struct scic_sds_controller *scic = ihost->core_controller; 1510cf89d1dSDan Williams unsigned long tmo = scic_controller_get_suggested_start_timeout(scic); 1526f231ddaSDan Williams 1530cf89d1dSDan Williams set_bit(IHOST_START_PENDING, &ihost->flags); 15477950f51SEdmund Nadolski 15577950f51SEdmund Nadolski spin_lock_irq(&ihost->scic_lock); 1560cf89d1dSDan Williams scic_controller_start(scic, tmo); 15777950f51SEdmund Nadolski scic_controller_enable_interrupts(scic); 15877950f51SEdmund Nadolski spin_unlock_irq(&ihost->scic_lock); 1596f231ddaSDan Williams } 1606f231ddaSDan Williams 1610cf89d1dSDan Williams void isci_host_stop_complete(struct isci_host *ihost, enum sci_status completion_status) 1626f231ddaSDan Williams { 1630cf89d1dSDan Williams isci_host_change_state(ihost, isci_stopped); 1640cf89d1dSDan Williams scic_controller_disable_interrupts(ihost->core_controller); 1650cf89d1dSDan Williams clear_bit(IHOST_STOP_PENDING, &ihost->flags); 1660cf89d1dSDan Williams wake_up(&ihost->eventq); 1676f231ddaSDan Williams } 1686f231ddaSDan Williams 1696f231ddaSDan Williams /** 1706f231ddaSDan Williams * isci_host_completion_routine() - This function is the delayed service 1716f231ddaSDan Williams * routine that calls the sci core library's completion handler. It's 1726f231ddaSDan Williams * scheduled as a tasklet from the interrupt service routine when interrupts 1736f231ddaSDan Williams * in use, or set as the timeout function in polled mode. 1746f231ddaSDan Williams * @data: This parameter specifies the ISCI host object 1756f231ddaSDan Williams * 1766f231ddaSDan Williams */ 1776f231ddaSDan Williams static void isci_host_completion_routine(unsigned long data) 1786f231ddaSDan Williams { 1796f231ddaSDan Williams struct isci_host *isci_host = (struct isci_host *)data; 1806f231ddaSDan Williams struct list_head completed_request_list; 18111b00c19SJeff Skirvin struct list_head errored_request_list; 1826f231ddaSDan Williams struct list_head *current_position; 1836f231ddaSDan Williams struct list_head *next_position; 1846f231ddaSDan Williams struct isci_request *request; 1856f231ddaSDan Williams struct isci_request *next_request; 1866f231ddaSDan Williams struct sas_task *task; 1876f231ddaSDan Williams 1886f231ddaSDan Williams INIT_LIST_HEAD(&completed_request_list); 18911b00c19SJeff Skirvin INIT_LIST_HEAD(&errored_request_list); 1906f231ddaSDan Williams 1916f231ddaSDan Williams spin_lock_irq(&isci_host->scic_lock); 1926f231ddaSDan Williams 193c7ef4031SDan Williams scic_sds_controller_completion_handler(isci_host->core_controller); 194c7ef4031SDan Williams 1956f231ddaSDan Williams /* Take the lists of completed I/Os from the host. */ 19611b00c19SJeff Skirvin 1976f231ddaSDan Williams list_splice_init(&isci_host->requests_to_complete, 1986f231ddaSDan Williams &completed_request_list); 1996f231ddaSDan Williams 20011b00c19SJeff Skirvin /* Take the list of errored I/Os from the host. */ 20111b00c19SJeff Skirvin list_splice_init(&isci_host->requests_to_errorback, 20211b00c19SJeff Skirvin &errored_request_list); 2036f231ddaSDan Williams 2046f231ddaSDan Williams spin_unlock_irq(&isci_host->scic_lock); 2056f231ddaSDan Williams 2066f231ddaSDan Williams /* Process any completions in the lists. */ 2076f231ddaSDan Williams list_for_each_safe(current_position, next_position, 2086f231ddaSDan Williams &completed_request_list) { 2096f231ddaSDan Williams 2106f231ddaSDan Williams request = list_entry(current_position, struct isci_request, 2116f231ddaSDan Williams completed_node); 2126f231ddaSDan Williams task = isci_request_access_task(request); 2136f231ddaSDan Williams 2146f231ddaSDan Williams /* Normal notification (task_done) */ 2156f231ddaSDan Williams dev_dbg(&isci_host->pdev->dev, 2166f231ddaSDan Williams "%s: Normal - request/task = %p/%p\n", 2176f231ddaSDan Williams __func__, 2186f231ddaSDan Williams request, 2196f231ddaSDan Williams task); 2206f231ddaSDan Williams 22111b00c19SJeff Skirvin /* Return the task to libsas */ 22211b00c19SJeff Skirvin if (task != NULL) { 2236f231ddaSDan Williams 22411b00c19SJeff Skirvin task->lldd_task = NULL; 22511b00c19SJeff Skirvin if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) { 22611b00c19SJeff Skirvin 22711b00c19SJeff Skirvin /* If the task is already in the abort path, 22811b00c19SJeff Skirvin * the task_done callback cannot be called. 22911b00c19SJeff Skirvin */ 23011b00c19SJeff Skirvin task->task_done(task); 23111b00c19SJeff Skirvin } 23211b00c19SJeff Skirvin } 2336f231ddaSDan Williams /* Free the request object. */ 2346f231ddaSDan Williams isci_request_free(isci_host, request); 2356f231ddaSDan Williams } 23611b00c19SJeff Skirvin list_for_each_entry_safe(request, next_request, &errored_request_list, 2376f231ddaSDan Williams completed_node) { 2386f231ddaSDan Williams 2396f231ddaSDan Williams task = isci_request_access_task(request); 2406f231ddaSDan Williams 2416f231ddaSDan Williams /* Use sas_task_abort */ 2426f231ddaSDan Williams dev_warn(&isci_host->pdev->dev, 2436f231ddaSDan Williams "%s: Error - request/task = %p/%p\n", 2446f231ddaSDan Williams __func__, 2456f231ddaSDan Williams request, 2466f231ddaSDan Williams task); 2476f231ddaSDan Williams 24811b00c19SJeff Skirvin if (task != NULL) { 24911b00c19SJeff Skirvin 25011b00c19SJeff Skirvin /* Put the task into the abort path if it's not there 25111b00c19SJeff Skirvin * already. 25211b00c19SJeff Skirvin */ 25311b00c19SJeff Skirvin if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) 2546f231ddaSDan Williams sas_task_abort(task); 25511b00c19SJeff Skirvin 25611b00c19SJeff Skirvin } else { 25711b00c19SJeff Skirvin /* This is a case where the request has completed with a 25811b00c19SJeff Skirvin * status such that it needed further target servicing, 25911b00c19SJeff Skirvin * but the sas_task reference has already been removed 26011b00c19SJeff Skirvin * from the request. Since it was errored, it was not 26111b00c19SJeff Skirvin * being aborted, so there is nothing to do except free 26211b00c19SJeff Skirvin * it. 26311b00c19SJeff Skirvin */ 26411b00c19SJeff Skirvin 26511b00c19SJeff Skirvin spin_lock_irq(&isci_host->scic_lock); 26611b00c19SJeff Skirvin /* Remove the request from the remote device's list 26711b00c19SJeff Skirvin * of pending requests. 26811b00c19SJeff Skirvin */ 26911b00c19SJeff Skirvin list_del_init(&request->dev_node); 27011b00c19SJeff Skirvin spin_unlock_irq(&isci_host->scic_lock); 27111b00c19SJeff Skirvin 27211b00c19SJeff Skirvin /* Free the request object. */ 27311b00c19SJeff Skirvin isci_request_free(isci_host, request); 27411b00c19SJeff Skirvin } 2756f231ddaSDan Williams } 2766f231ddaSDan Williams 2776f231ddaSDan Williams } 2786f231ddaSDan Williams 2790cf89d1dSDan Williams void isci_host_deinit(struct isci_host *ihost) 2806f231ddaSDan Williams { 2810cf89d1dSDan Williams struct scic_sds_controller *scic = ihost->core_controller; 2826f231ddaSDan Williams int i; 2836f231ddaSDan Williams 2840cf89d1dSDan Williams isci_host_change_state(ihost, isci_stopping); 2856f231ddaSDan Williams for (i = 0; i < SCI_MAX_PORTS; i++) { 2860cf89d1dSDan Williams struct isci_port *port = &ihost->isci_ports[i]; 2870cf89d1dSDan Williams struct isci_remote_device *idev, *d; 2880cf89d1dSDan Williams 2890cf89d1dSDan Williams list_for_each_entry_safe(idev, d, &port->remote_dev_list, node) { 2900cf89d1dSDan Williams isci_remote_device_change_state(idev, isci_stopping); 2916ad31fecSDan Williams isci_remote_device_stop(ihost, idev); 2926f231ddaSDan Williams } 2936f231ddaSDan Williams } 2946f231ddaSDan Williams 2950cf89d1dSDan Williams set_bit(IHOST_STOP_PENDING, &ihost->flags); 2967c40a803SDan Williams 2977c40a803SDan Williams spin_lock_irq(&ihost->scic_lock); 2980cf89d1dSDan Williams scic_controller_stop(scic, SCIC_CONTROLLER_STOP_TIMEOUT); 2997c40a803SDan Williams spin_unlock_irq(&ihost->scic_lock); 3007c40a803SDan Williams 3010cf89d1dSDan Williams wait_for_stop(ihost); 3020cf89d1dSDan Williams scic_controller_reset(scic); 3037c40a803SDan Williams isci_timer_list_destroy(ihost); 3046f231ddaSDan Williams } 3056f231ddaSDan Williams 3066f231ddaSDan Williams static void __iomem *scu_base(struct isci_host *isci_host) 3076f231ddaSDan Williams { 3086f231ddaSDan Williams struct pci_dev *pdev = isci_host->pdev; 3096f231ddaSDan Williams int id = isci_host->id; 3106f231ddaSDan Williams 3116f231ddaSDan Williams return pcim_iomap_table(pdev)[SCI_SCU_BAR * 2] + SCI_SCU_BAR_SIZE * id; 3126f231ddaSDan Williams } 3136f231ddaSDan Williams 3146f231ddaSDan Williams static void __iomem *smu_base(struct isci_host *isci_host) 3156f231ddaSDan Williams { 3166f231ddaSDan Williams struct pci_dev *pdev = isci_host->pdev; 3176f231ddaSDan Williams int id = isci_host->id; 3186f231ddaSDan Williams 3196f231ddaSDan Williams return pcim_iomap_table(pdev)[SCI_SMU_BAR * 2] + SCI_SMU_BAR_SIZE * id; 3206f231ddaSDan Williams } 3216f231ddaSDan Williams 322b5f18a20SDave Jiang static void isci_user_parameters_get( 323b5f18a20SDave Jiang struct isci_host *isci_host, 324b5f18a20SDave Jiang union scic_user_parameters *scic_user_params) 325b5f18a20SDave Jiang { 326b5f18a20SDave Jiang struct scic_sds_user_parameters *u = &scic_user_params->sds1; 327b5f18a20SDave Jiang int i; 328b5f18a20SDave Jiang 329b5f18a20SDave Jiang for (i = 0; i < SCI_MAX_PHYS; i++) { 330b5f18a20SDave Jiang struct sci_phy_user_params *u_phy = &u->phys[i]; 331b5f18a20SDave Jiang 332b5f18a20SDave Jiang u_phy->max_speed_generation = phy_gen; 333b5f18a20SDave Jiang 334b5f18a20SDave Jiang /* we are not exporting these for now */ 335b5f18a20SDave Jiang u_phy->align_insertion_frequency = 0x7f; 336b5f18a20SDave Jiang u_phy->in_connection_align_insertion_frequency = 0xff; 337b5f18a20SDave Jiang u_phy->notify_enable_spin_up_insertion_frequency = 0x33; 338b5f18a20SDave Jiang } 339b5f18a20SDave Jiang 340b5f18a20SDave Jiang u->stp_inactivity_timeout = stp_inactive_to; 341b5f18a20SDave Jiang u->ssp_inactivity_timeout = ssp_inactive_to; 342b5f18a20SDave Jiang u->stp_max_occupancy_timeout = stp_max_occ_to; 343b5f18a20SDave Jiang u->ssp_max_occupancy_timeout = ssp_max_occ_to; 344b5f18a20SDave Jiang u->no_outbound_task_timeout = no_outbound_task_to; 345b5f18a20SDave Jiang u->max_number_concurrent_device_spin_up = max_concurr_spinup; 346b5f18a20SDave Jiang } 347b5f18a20SDave Jiang 3486f231ddaSDan Williams int isci_host_init(struct isci_host *isci_host) 3496f231ddaSDan Williams { 350d9c37390SDan Williams int err = 0, i; 3516f231ddaSDan Williams enum sci_status status; 3526f231ddaSDan Williams struct scic_sds_controller *controller; 3534711ba10SDan Williams union scic_oem_parameters oem; 3546f231ddaSDan Williams union scic_user_parameters scic_user_params; 355d044af17SDan Williams struct isci_pci_info *pci_info = to_pci_info(isci_host->pdev); 3566f231ddaSDan Williams 3577c40a803SDan Williams isci_timer_list_construct(isci_host); 3586f231ddaSDan Williams 3596f231ddaSDan Williams controller = scic_controller_alloc(&isci_host->pdev->dev); 3606f231ddaSDan Williams 3616f231ddaSDan Williams if (!controller) { 362858d4aa7SDave Jiang dev_err(&isci_host->pdev->dev, 363858d4aa7SDave Jiang "%s: failed (%d)\n", 364858d4aa7SDave Jiang __func__, 365858d4aa7SDave Jiang err); 366858d4aa7SDave Jiang return -ENOMEM; 3676f231ddaSDan Williams } 3686f231ddaSDan Williams 3696f231ddaSDan Williams isci_host->core_controller = controller; 3704711ba10SDan Williams sci_object_set_association(isci_host->core_controller, isci_host); 3716f231ddaSDan Williams spin_lock_init(&isci_host->state_lock); 3726f231ddaSDan Williams spin_lock_init(&isci_host->scic_lock); 3736f231ddaSDan Williams spin_lock_init(&isci_host->queue_lock); 3740cf89d1dSDan Williams init_waitqueue_head(&isci_host->eventq); 3756f231ddaSDan Williams 3766f231ddaSDan Williams isci_host_change_state(isci_host, isci_starting); 3776f231ddaSDan Williams isci_host->can_queue = ISCI_CAN_QUEUE_VAL; 3786f231ddaSDan Williams 3796f231ddaSDan Williams status = scic_controller_construct(controller, scu_base(isci_host), 3806f231ddaSDan Williams smu_base(isci_host)); 3816f231ddaSDan Williams 3826f231ddaSDan Williams if (status != SCI_SUCCESS) { 3836f231ddaSDan Williams dev_err(&isci_host->pdev->dev, 3846f231ddaSDan Williams "%s: scic_controller_construct failed - status = %x\n", 3856f231ddaSDan Williams __func__, 3866f231ddaSDan Williams status); 387858d4aa7SDave Jiang return -ENODEV; 3886f231ddaSDan Williams } 3896f231ddaSDan Williams 3906f231ddaSDan Williams isci_host->sas_ha.dev = &isci_host->pdev->dev; 3916f231ddaSDan Williams isci_host->sas_ha.lldd_ha = isci_host; 3926f231ddaSDan Williams 393d044af17SDan Williams /* 394d044af17SDan Williams * grab initial values stored in the controller object for OEM and USER 395d044af17SDan Williams * parameters 396d044af17SDan Williams */ 397b5f18a20SDave Jiang isci_user_parameters_get(isci_host, &scic_user_params); 398d044af17SDan Williams status = scic_user_parameters_set(isci_host->core_controller, 399d044af17SDan Williams &scic_user_params); 400d044af17SDan Williams if (status != SCI_SUCCESS) { 401d044af17SDan Williams dev_warn(&isci_host->pdev->dev, 402d044af17SDan Williams "%s: scic_user_parameters_set failed\n", 403d044af17SDan Williams __func__); 404d044af17SDan Williams return -ENODEV; 405d044af17SDan Williams } 4066f231ddaSDan Williams 4074711ba10SDan Williams scic_oem_parameters_get(controller, &oem); 408d044af17SDan Williams 409d044af17SDan Williams /* grab any OEM parameters specified in orom */ 410d044af17SDan Williams if (pci_info->orom) { 4114711ba10SDan Williams status = isci_parse_oem_parameters(&oem, 412d044af17SDan Williams pci_info->orom, 413d044af17SDan Williams isci_host->id); 4146f231ddaSDan Williams if (status != SCI_SUCCESS) { 4156f231ddaSDan Williams dev_warn(&isci_host->pdev->dev, 4166f231ddaSDan Williams "parsing firmware oem parameters failed\n"); 417858d4aa7SDave Jiang return -EINVAL; 4186f231ddaSDan Williams } 4194711ba10SDan Williams } 4204711ba10SDan Williams 4214711ba10SDan Williams status = scic_oem_parameters_set(isci_host->core_controller, &oem); 4226f231ddaSDan Williams if (status != SCI_SUCCESS) { 4236f231ddaSDan Williams dev_warn(&isci_host->pdev->dev, 4246f231ddaSDan Williams "%s: scic_oem_parameters_set failed\n", 4256f231ddaSDan Williams __func__); 426858d4aa7SDave Jiang return -ENODEV; 4276f231ddaSDan Williams } 4286f231ddaSDan Williams 4296f231ddaSDan Williams tasklet_init(&isci_host->completion_tasklet, 430c7ef4031SDan Williams isci_host_completion_routine, (unsigned long)isci_host); 4316f231ddaSDan Williams 4326f231ddaSDan Williams INIT_LIST_HEAD(&isci_host->requests_to_complete); 43311b00c19SJeff Skirvin INIT_LIST_HEAD(&isci_host->requests_to_errorback); 4346f231ddaSDan Williams 4357c40a803SDan Williams spin_lock_irq(&isci_host->scic_lock); 4367c40a803SDan Williams status = scic_controller_initialize(isci_host->core_controller); 4377c40a803SDan Williams spin_unlock_irq(&isci_host->scic_lock); 4387c40a803SDan Williams if (status != SCI_SUCCESS) { 4397c40a803SDan Williams dev_warn(&isci_host->pdev->dev, 4407c40a803SDan Williams "%s: scic_controller_initialize failed -" 4417c40a803SDan Williams " status = 0x%x\n", 4427c40a803SDan Williams __func__, status); 4437c40a803SDan Williams return -ENODEV; 4447c40a803SDan Williams } 4457c40a803SDan Williams 446bc5c9674SChristoph Hellwig err = scic_controller_mem_init(isci_host->core_controller); 4476f231ddaSDan Williams if (err) 448858d4aa7SDave Jiang return err; 4496f231ddaSDan Williams 4506f231ddaSDan Williams /* 4516f231ddaSDan Williams * keep the pool alloc size around, will use it for a bounds checking 4526f231ddaSDan Williams * when trying to convert virtual addresses to physical addresses 4536f231ddaSDan Williams */ 4546f231ddaSDan Williams isci_host->dma_pool_alloc_size = sizeof(struct isci_request) + 4556f231ddaSDan Williams scic_io_request_get_object_size(); 4566f231ddaSDan Williams isci_host->dma_pool = dmam_pool_create(DRV_NAME, &isci_host->pdev->dev, 4576f231ddaSDan Williams isci_host->dma_pool_alloc_size, 4586f231ddaSDan Williams SLAB_HWCACHE_ALIGN, 0); 4596f231ddaSDan Williams 460858d4aa7SDave Jiang if (!isci_host->dma_pool) 461858d4aa7SDave Jiang return -ENOMEM; 4626f231ddaSDan Williams 463d9c37390SDan Williams for (i = 0; i < SCI_MAX_PORTS; i++) 464d9c37390SDan Williams isci_port_init(&isci_host->isci_ports[i], isci_host, i); 4656f231ddaSDan Williams 466d9c37390SDan Williams for (i = 0; i < SCI_MAX_PHYS; i++) 467d9c37390SDan Williams isci_phy_init(&isci_host->phys[i], isci_host, i); 468d9c37390SDan Williams 469d9c37390SDan Williams for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) { 470*57f20f4eSDan Williams struct isci_remote_device *idev = &isci_host->devices[i]; 471d9c37390SDan Williams 472d9c37390SDan Williams INIT_LIST_HEAD(&idev->reqs_in_process); 473d9c37390SDan Williams INIT_LIST_HEAD(&idev->node); 474d9c37390SDan Williams spin_lock_init(&idev->state_lock); 475d9c37390SDan Williams } 4766f231ddaSDan Williams 477858d4aa7SDave Jiang return 0; 4786f231ddaSDan Williams } 479