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_port.h" 596f231ddaSDan Williams #include "port.h" 606f231ddaSDan Williams #include "request.h" 616f231ddaSDan Williams #include "host.h" 62d044af17SDan Williams #include "probe_roms.h" 6388f3b62aSDan Williams #include "scic_sds_controller.h" 646f231ddaSDan Williams 65c7ef4031SDan Williams irqreturn_t isci_msix_isr(int vec, void *data) 666f231ddaSDan Williams { 67c7ef4031SDan Williams struct isci_host *ihost = data; 686f231ddaSDan Williams 69cc3dbd0aSArtur Wojcik if (scic_sds_controller_isr(&ihost->sci)) 70c7ef4031SDan Williams tasklet_schedule(&ihost->completion_tasklet); 716f231ddaSDan Williams 72c7ef4031SDan Williams return IRQ_HANDLED; 73c7ef4031SDan Williams } 74c7ef4031SDan Williams 75c7ef4031SDan Williams irqreturn_t isci_intx_isr(int vec, void *data) 766f231ddaSDan Williams { 776f231ddaSDan Williams irqreturn_t ret = IRQ_NONE; 7831e824edSDan Williams struct isci_host *ihost = data; 79cc3dbd0aSArtur Wojcik struct scic_sds_controller *scic = &ihost->sci; 806f231ddaSDan Williams 81c7ef4031SDan Williams if (scic_sds_controller_isr(scic)) { 8231e824edSDan Williams writel(SMU_ISR_COMPLETION, &scic->smu_registers->interrupt_status); 83c7ef4031SDan Williams tasklet_schedule(&ihost->completion_tasklet); 846f231ddaSDan Williams ret = IRQ_HANDLED; 8592f4f0f5SDan Williams } else if (scic_sds_controller_error_isr(scic)) { 8692f4f0f5SDan Williams spin_lock(&ihost->scic_lock); 8792f4f0f5SDan Williams scic_sds_controller_error_handler(scic); 8892f4f0f5SDan Williams spin_unlock(&ihost->scic_lock); 8992f4f0f5SDan Williams ret = IRQ_HANDLED; 906f231ddaSDan Williams } 9192f4f0f5SDan Williams 926f231ddaSDan Williams return ret; 936f231ddaSDan Williams } 946f231ddaSDan Williams 9592f4f0f5SDan Williams irqreturn_t isci_error_isr(int vec, void *data) 9692f4f0f5SDan Williams { 9792f4f0f5SDan Williams struct isci_host *ihost = data; 9892f4f0f5SDan Williams 99cc3dbd0aSArtur Wojcik if (scic_sds_controller_error_isr(&ihost->sci)) 100cc3dbd0aSArtur Wojcik scic_sds_controller_error_handler(&ihost->sci); 10192f4f0f5SDan Williams 10292f4f0f5SDan Williams return IRQ_HANDLED; 10392f4f0f5SDan Williams } 1046f231ddaSDan Williams 1056f231ddaSDan Williams /** 1066f231ddaSDan Williams * isci_host_start_complete() - This function is called by the core library, 1076f231ddaSDan Williams * through the ISCI Module, to indicate controller start status. 1086f231ddaSDan Williams * @isci_host: This parameter specifies the ISCI host object 1096f231ddaSDan Williams * @completion_status: This parameter specifies the completion status from the 1106f231ddaSDan Williams * core library. 1116f231ddaSDan Williams * 1126f231ddaSDan Williams */ 1130cf89d1dSDan Williams void isci_host_start_complete(struct isci_host *ihost, enum sci_status completion_status) 1146f231ddaSDan Williams { 1150cf89d1dSDan Williams if (completion_status != SCI_SUCCESS) 1160cf89d1dSDan Williams dev_info(&ihost->pdev->dev, 1170cf89d1dSDan Williams "controller start timed out, continuing...\n"); 1180cf89d1dSDan Williams isci_host_change_state(ihost, isci_ready); 1190cf89d1dSDan Williams clear_bit(IHOST_START_PENDING, &ihost->flags); 1200cf89d1dSDan Williams wake_up(&ihost->eventq); 1216f231ddaSDan Williams } 1226f231ddaSDan Williams 123c7ef4031SDan Williams int isci_host_scan_finished(struct Scsi_Host *shost, unsigned long time) 1246f231ddaSDan Williams { 1254393aa4eSDan Williams struct isci_host *ihost = SHOST_TO_SAS_HA(shost)->lldd_ha; 1266f231ddaSDan Williams 12777950f51SEdmund Nadolski if (test_bit(IHOST_START_PENDING, &ihost->flags)) 1286f231ddaSDan Williams return 0; 1296f231ddaSDan Williams 13077950f51SEdmund Nadolski /* todo: use sas_flush_discovery once it is upstream */ 13177950f51SEdmund Nadolski scsi_flush_work(shost); 13277950f51SEdmund Nadolski 13377950f51SEdmund Nadolski scsi_flush_work(shost); 1346f231ddaSDan Williams 1350cf89d1dSDan Williams dev_dbg(&ihost->pdev->dev, 1360cf89d1dSDan Williams "%s: ihost->status = %d, time = %ld\n", 1370cf89d1dSDan Williams __func__, isci_host_get_state(ihost), time); 1386f231ddaSDan Williams 1396f231ddaSDan Williams return 1; 1406f231ddaSDan Williams 1416f231ddaSDan Williams } 1426f231ddaSDan Williams 1436f231ddaSDan Williams void isci_host_scan_start(struct Scsi_Host *shost) 1446f231ddaSDan Williams { 1454393aa4eSDan Williams struct isci_host *ihost = SHOST_TO_SAS_HA(shost)->lldd_ha; 146cc3dbd0aSArtur Wojcik unsigned long tmo = scic_controller_get_suggested_start_timeout(&ihost->sci); 1476f231ddaSDan Williams 1480cf89d1dSDan Williams set_bit(IHOST_START_PENDING, &ihost->flags); 14977950f51SEdmund Nadolski 15077950f51SEdmund Nadolski spin_lock_irq(&ihost->scic_lock); 151cc3dbd0aSArtur Wojcik scic_controller_start(&ihost->sci, tmo); 152cc3dbd0aSArtur Wojcik scic_controller_enable_interrupts(&ihost->sci); 15377950f51SEdmund Nadolski spin_unlock_irq(&ihost->scic_lock); 1546f231ddaSDan Williams } 1556f231ddaSDan Williams 1560cf89d1dSDan Williams void isci_host_stop_complete(struct isci_host *ihost, enum sci_status completion_status) 1576f231ddaSDan Williams { 1580cf89d1dSDan Williams isci_host_change_state(ihost, isci_stopped); 159cc3dbd0aSArtur Wojcik scic_controller_disable_interrupts(&ihost->sci); 1600cf89d1dSDan Williams clear_bit(IHOST_STOP_PENDING, &ihost->flags); 1610cf89d1dSDan Williams wake_up(&ihost->eventq); 1626f231ddaSDan Williams } 1636f231ddaSDan Williams 1646f231ddaSDan Williams /** 1656f231ddaSDan Williams * isci_host_completion_routine() - This function is the delayed service 1666f231ddaSDan Williams * routine that calls the sci core library's completion handler. It's 1676f231ddaSDan Williams * scheduled as a tasklet from the interrupt service routine when interrupts 1686f231ddaSDan Williams * in use, or set as the timeout function in polled mode. 1696f231ddaSDan Williams * @data: This parameter specifies the ISCI host object 1706f231ddaSDan Williams * 1716f231ddaSDan Williams */ 1726f231ddaSDan Williams static void isci_host_completion_routine(unsigned long data) 1736f231ddaSDan Williams { 1746f231ddaSDan Williams struct isci_host *isci_host = (struct isci_host *)data; 1756f231ddaSDan Williams struct list_head completed_request_list; 17611b00c19SJeff Skirvin struct list_head errored_request_list; 1776f231ddaSDan Williams struct list_head *current_position; 1786f231ddaSDan Williams struct list_head *next_position; 1796f231ddaSDan Williams struct isci_request *request; 1806f231ddaSDan Williams struct isci_request *next_request; 1816f231ddaSDan Williams struct sas_task *task; 1826f231ddaSDan Williams 1836f231ddaSDan Williams INIT_LIST_HEAD(&completed_request_list); 18411b00c19SJeff Skirvin INIT_LIST_HEAD(&errored_request_list); 1856f231ddaSDan Williams 1866f231ddaSDan Williams spin_lock_irq(&isci_host->scic_lock); 1876f231ddaSDan Williams 188cc3dbd0aSArtur Wojcik scic_sds_controller_completion_handler(&isci_host->sci); 189c7ef4031SDan Williams 1906f231ddaSDan Williams /* Take the lists of completed I/Os from the host. */ 19111b00c19SJeff Skirvin 1926f231ddaSDan Williams list_splice_init(&isci_host->requests_to_complete, 1936f231ddaSDan Williams &completed_request_list); 1946f231ddaSDan Williams 19511b00c19SJeff Skirvin /* Take the list of errored I/Os from the host. */ 19611b00c19SJeff Skirvin list_splice_init(&isci_host->requests_to_errorback, 19711b00c19SJeff Skirvin &errored_request_list); 1986f231ddaSDan Williams 1996f231ddaSDan Williams spin_unlock_irq(&isci_host->scic_lock); 2006f231ddaSDan Williams 2016f231ddaSDan Williams /* Process any completions in the lists. */ 2026f231ddaSDan Williams list_for_each_safe(current_position, next_position, 2036f231ddaSDan Williams &completed_request_list) { 2046f231ddaSDan Williams 2056f231ddaSDan Williams request = list_entry(current_position, struct isci_request, 2066f231ddaSDan Williams completed_node); 2076f231ddaSDan Williams task = isci_request_access_task(request); 2086f231ddaSDan Williams 2096f231ddaSDan Williams /* Normal notification (task_done) */ 2106f231ddaSDan Williams dev_dbg(&isci_host->pdev->dev, 2116f231ddaSDan Williams "%s: Normal - request/task = %p/%p\n", 2126f231ddaSDan Williams __func__, 2136f231ddaSDan Williams request, 2146f231ddaSDan Williams task); 2156f231ddaSDan Williams 21611b00c19SJeff Skirvin /* Return the task to libsas */ 21711b00c19SJeff Skirvin if (task != NULL) { 2186f231ddaSDan Williams 21911b00c19SJeff Skirvin task->lldd_task = NULL; 22011b00c19SJeff Skirvin if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) { 22111b00c19SJeff Skirvin 22211b00c19SJeff Skirvin /* If the task is already in the abort path, 22311b00c19SJeff Skirvin * the task_done callback cannot be called. 22411b00c19SJeff Skirvin */ 22511b00c19SJeff Skirvin task->task_done(task); 22611b00c19SJeff Skirvin } 22711b00c19SJeff Skirvin } 2286f231ddaSDan Williams /* Free the request object. */ 2296f231ddaSDan Williams isci_request_free(isci_host, request); 2306f231ddaSDan Williams } 23111b00c19SJeff Skirvin list_for_each_entry_safe(request, next_request, &errored_request_list, 2326f231ddaSDan Williams completed_node) { 2336f231ddaSDan Williams 2346f231ddaSDan Williams task = isci_request_access_task(request); 2356f231ddaSDan Williams 2366f231ddaSDan Williams /* Use sas_task_abort */ 2376f231ddaSDan Williams dev_warn(&isci_host->pdev->dev, 2386f231ddaSDan Williams "%s: Error - request/task = %p/%p\n", 2396f231ddaSDan Williams __func__, 2406f231ddaSDan Williams request, 2416f231ddaSDan Williams task); 2426f231ddaSDan Williams 24311b00c19SJeff Skirvin if (task != NULL) { 24411b00c19SJeff Skirvin 24511b00c19SJeff Skirvin /* Put the task into the abort path if it's not there 24611b00c19SJeff Skirvin * already. 24711b00c19SJeff Skirvin */ 24811b00c19SJeff Skirvin if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) 2496f231ddaSDan Williams sas_task_abort(task); 25011b00c19SJeff Skirvin 25111b00c19SJeff Skirvin } else { 25211b00c19SJeff Skirvin /* This is a case where the request has completed with a 25311b00c19SJeff Skirvin * status such that it needed further target servicing, 25411b00c19SJeff Skirvin * but the sas_task reference has already been removed 25511b00c19SJeff Skirvin * from the request. Since it was errored, it was not 25611b00c19SJeff Skirvin * being aborted, so there is nothing to do except free 25711b00c19SJeff Skirvin * it. 25811b00c19SJeff Skirvin */ 25911b00c19SJeff Skirvin 26011b00c19SJeff Skirvin spin_lock_irq(&isci_host->scic_lock); 26111b00c19SJeff Skirvin /* Remove the request from the remote device's list 26211b00c19SJeff Skirvin * of pending requests. 26311b00c19SJeff Skirvin */ 26411b00c19SJeff Skirvin list_del_init(&request->dev_node); 26511b00c19SJeff Skirvin spin_unlock_irq(&isci_host->scic_lock); 26611b00c19SJeff Skirvin 26711b00c19SJeff Skirvin /* Free the request object. */ 26811b00c19SJeff Skirvin isci_request_free(isci_host, request); 26911b00c19SJeff Skirvin } 2706f231ddaSDan Williams } 2716f231ddaSDan Williams 2726f231ddaSDan Williams } 2736f231ddaSDan Williams 2740cf89d1dSDan Williams void isci_host_deinit(struct isci_host *ihost) 2756f231ddaSDan Williams { 2766f231ddaSDan Williams int i; 2776f231ddaSDan Williams 2780cf89d1dSDan Williams isci_host_change_state(ihost, isci_stopping); 2796f231ddaSDan Williams for (i = 0; i < SCI_MAX_PORTS; i++) { 280e531381eSDan Williams struct isci_port *iport = &ihost->ports[i]; 2810cf89d1dSDan Williams struct isci_remote_device *idev, *d; 2820cf89d1dSDan Williams 283e531381eSDan Williams list_for_each_entry_safe(idev, d, &iport->remote_dev_list, node) { 2840cf89d1dSDan Williams isci_remote_device_change_state(idev, isci_stopping); 2856ad31fecSDan Williams isci_remote_device_stop(ihost, idev); 2866f231ddaSDan Williams } 2876f231ddaSDan Williams } 2886f231ddaSDan Williams 2890cf89d1dSDan Williams set_bit(IHOST_STOP_PENDING, &ihost->flags); 2907c40a803SDan Williams 2917c40a803SDan Williams spin_lock_irq(&ihost->scic_lock); 292cc3dbd0aSArtur Wojcik scic_controller_stop(&ihost->sci, SCIC_CONTROLLER_STOP_TIMEOUT); 2937c40a803SDan Williams spin_unlock_irq(&ihost->scic_lock); 2947c40a803SDan Williams 2950cf89d1dSDan Williams wait_for_stop(ihost); 296cc3dbd0aSArtur Wojcik scic_controller_reset(&ihost->sci); 2977c40a803SDan Williams isci_timer_list_destroy(ihost); 2986f231ddaSDan Williams } 2996f231ddaSDan Williams 3006f231ddaSDan Williams static void __iomem *scu_base(struct isci_host *isci_host) 3016f231ddaSDan Williams { 3026f231ddaSDan Williams struct pci_dev *pdev = isci_host->pdev; 3036f231ddaSDan Williams int id = isci_host->id; 3046f231ddaSDan Williams 3056f231ddaSDan Williams return pcim_iomap_table(pdev)[SCI_SCU_BAR * 2] + SCI_SCU_BAR_SIZE * id; 3066f231ddaSDan Williams } 3076f231ddaSDan Williams 3086f231ddaSDan Williams static void __iomem *smu_base(struct isci_host *isci_host) 3096f231ddaSDan Williams { 3106f231ddaSDan Williams struct pci_dev *pdev = isci_host->pdev; 3116f231ddaSDan Williams int id = isci_host->id; 3126f231ddaSDan Williams 3136f231ddaSDan Williams return pcim_iomap_table(pdev)[SCI_SMU_BAR * 2] + SCI_SMU_BAR_SIZE * id; 3146f231ddaSDan Williams } 3156f231ddaSDan Williams 316b5f18a20SDave Jiang static void isci_user_parameters_get( 317b5f18a20SDave Jiang struct isci_host *isci_host, 318b5f18a20SDave Jiang union scic_user_parameters *scic_user_params) 319b5f18a20SDave Jiang { 320b5f18a20SDave Jiang struct scic_sds_user_parameters *u = &scic_user_params->sds1; 321b5f18a20SDave Jiang int i; 322b5f18a20SDave Jiang 323b5f18a20SDave Jiang for (i = 0; i < SCI_MAX_PHYS; i++) { 324b5f18a20SDave Jiang struct sci_phy_user_params *u_phy = &u->phys[i]; 325b5f18a20SDave Jiang 326b5f18a20SDave Jiang u_phy->max_speed_generation = phy_gen; 327b5f18a20SDave Jiang 328b5f18a20SDave Jiang /* we are not exporting these for now */ 329b5f18a20SDave Jiang u_phy->align_insertion_frequency = 0x7f; 330b5f18a20SDave Jiang u_phy->in_connection_align_insertion_frequency = 0xff; 331b5f18a20SDave Jiang u_phy->notify_enable_spin_up_insertion_frequency = 0x33; 332b5f18a20SDave Jiang } 333b5f18a20SDave Jiang 334b5f18a20SDave Jiang u->stp_inactivity_timeout = stp_inactive_to; 335b5f18a20SDave Jiang u->ssp_inactivity_timeout = ssp_inactive_to; 336b5f18a20SDave Jiang u->stp_max_occupancy_timeout = stp_max_occ_to; 337b5f18a20SDave Jiang u->ssp_max_occupancy_timeout = ssp_max_occ_to; 338b5f18a20SDave Jiang u->no_outbound_task_timeout = no_outbound_task_to; 339b5f18a20SDave Jiang u->max_number_concurrent_device_spin_up = max_concurr_spinup; 340b5f18a20SDave Jiang } 341b5f18a20SDave Jiang 3426f231ddaSDan Williams int isci_host_init(struct isci_host *isci_host) 3436f231ddaSDan Williams { 344d9c37390SDan Williams int err = 0, i; 3456f231ddaSDan Williams enum sci_status status; 3464711ba10SDan Williams union scic_oem_parameters oem; 3476f231ddaSDan Williams union scic_user_parameters scic_user_params; 348d044af17SDan Williams struct isci_pci_info *pci_info = to_pci_info(isci_host->pdev); 3496f231ddaSDan Williams 3507c40a803SDan Williams isci_timer_list_construct(isci_host); 3516f231ddaSDan Williams 3526f231ddaSDan Williams spin_lock_init(&isci_host->state_lock); 3536f231ddaSDan Williams spin_lock_init(&isci_host->scic_lock); 3546f231ddaSDan Williams spin_lock_init(&isci_host->queue_lock); 3550cf89d1dSDan Williams init_waitqueue_head(&isci_host->eventq); 3566f231ddaSDan Williams 3576f231ddaSDan Williams isci_host_change_state(isci_host, isci_starting); 3586f231ddaSDan Williams isci_host->can_queue = ISCI_CAN_QUEUE_VAL; 3596f231ddaSDan Williams 360cc3dbd0aSArtur Wojcik status = scic_controller_construct(&isci_host->sci, scu_base(isci_host), 3616f231ddaSDan Williams smu_base(isci_host)); 3626f231ddaSDan Williams 3636f231ddaSDan Williams if (status != SCI_SUCCESS) { 3646f231ddaSDan Williams dev_err(&isci_host->pdev->dev, 3656f231ddaSDan Williams "%s: scic_controller_construct failed - status = %x\n", 3666f231ddaSDan Williams __func__, 3676f231ddaSDan Williams status); 368858d4aa7SDave Jiang return -ENODEV; 3696f231ddaSDan Williams } 3706f231ddaSDan Williams 3716f231ddaSDan Williams isci_host->sas_ha.dev = &isci_host->pdev->dev; 3726f231ddaSDan Williams isci_host->sas_ha.lldd_ha = isci_host; 3736f231ddaSDan Williams 374d044af17SDan Williams /* 375d044af17SDan Williams * grab initial values stored in the controller object for OEM and USER 376d044af17SDan Williams * parameters 377d044af17SDan Williams */ 378b5f18a20SDave Jiang isci_user_parameters_get(isci_host, &scic_user_params); 379cc3dbd0aSArtur Wojcik status = scic_user_parameters_set(&isci_host->sci, 380d044af17SDan Williams &scic_user_params); 381d044af17SDan Williams if (status != SCI_SUCCESS) { 382d044af17SDan Williams dev_warn(&isci_host->pdev->dev, 383d044af17SDan Williams "%s: scic_user_parameters_set failed\n", 384d044af17SDan Williams __func__); 385d044af17SDan Williams return -ENODEV; 386d044af17SDan Williams } 3876f231ddaSDan Williams 388cc3dbd0aSArtur Wojcik scic_oem_parameters_get(&isci_host->sci, &oem); 389d044af17SDan Williams 390d044af17SDan Williams /* grab any OEM parameters specified in orom */ 391d044af17SDan Williams if (pci_info->orom) { 3924711ba10SDan Williams status = isci_parse_oem_parameters(&oem, 393d044af17SDan Williams pci_info->orom, 394d044af17SDan Williams isci_host->id); 3956f231ddaSDan Williams if (status != SCI_SUCCESS) { 3966f231ddaSDan Williams dev_warn(&isci_host->pdev->dev, 3976f231ddaSDan Williams "parsing firmware oem parameters failed\n"); 398858d4aa7SDave Jiang return -EINVAL; 3996f231ddaSDan Williams } 4004711ba10SDan Williams } 4014711ba10SDan Williams 402cc3dbd0aSArtur Wojcik status = scic_oem_parameters_set(&isci_host->sci, &oem); 4036f231ddaSDan Williams if (status != SCI_SUCCESS) { 4046f231ddaSDan Williams dev_warn(&isci_host->pdev->dev, 4056f231ddaSDan Williams "%s: scic_oem_parameters_set failed\n", 4066f231ddaSDan Williams __func__); 407858d4aa7SDave Jiang return -ENODEV; 4086f231ddaSDan Williams } 4096f231ddaSDan Williams 4106f231ddaSDan Williams tasklet_init(&isci_host->completion_tasklet, 411c7ef4031SDan Williams isci_host_completion_routine, (unsigned long)isci_host); 4126f231ddaSDan Williams 4136f231ddaSDan Williams INIT_LIST_HEAD(&isci_host->requests_to_complete); 41411b00c19SJeff Skirvin INIT_LIST_HEAD(&isci_host->requests_to_errorback); 4156f231ddaSDan Williams 4167c40a803SDan Williams spin_lock_irq(&isci_host->scic_lock); 417cc3dbd0aSArtur Wojcik status = scic_controller_initialize(&isci_host->sci); 4187c40a803SDan Williams spin_unlock_irq(&isci_host->scic_lock); 4197c40a803SDan Williams if (status != SCI_SUCCESS) { 4207c40a803SDan Williams dev_warn(&isci_host->pdev->dev, 4217c40a803SDan Williams "%s: scic_controller_initialize failed -" 4227c40a803SDan Williams " status = 0x%x\n", 4237c40a803SDan Williams __func__, status); 4247c40a803SDan Williams return -ENODEV; 4257c40a803SDan Williams } 4267c40a803SDan Williams 427cc3dbd0aSArtur Wojcik err = scic_controller_mem_init(&isci_host->sci); 4286f231ddaSDan Williams if (err) 429858d4aa7SDave Jiang return err; 4306f231ddaSDan Williams 4316f231ddaSDan Williams isci_host->dma_pool = dmam_pool_create(DRV_NAME, &isci_host->pdev->dev, 432*67ea838dSDan Williams sizeof(struct isci_request), 4336f231ddaSDan Williams SLAB_HWCACHE_ALIGN, 0); 4346f231ddaSDan Williams 435858d4aa7SDave Jiang if (!isci_host->dma_pool) 436858d4aa7SDave Jiang return -ENOMEM; 4376f231ddaSDan Williams 438d9c37390SDan Williams for (i = 0; i < SCI_MAX_PORTS; i++) 439e531381eSDan Williams isci_port_init(&isci_host->ports[i], isci_host, i); 4406f231ddaSDan Williams 441d9c37390SDan Williams for (i = 0; i < SCI_MAX_PHYS; i++) 442d9c37390SDan Williams isci_phy_init(&isci_host->phys[i], isci_host, i); 443d9c37390SDan Williams 444d9c37390SDan Williams for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) { 44557f20f4eSDan Williams struct isci_remote_device *idev = &isci_host->devices[i]; 446d9c37390SDan Williams 447d9c37390SDan Williams INIT_LIST_HEAD(&idev->reqs_in_process); 448d9c37390SDan Williams INIT_LIST_HEAD(&idev->node); 449d9c37390SDan Williams spin_lock_init(&idev->state_lock); 450d9c37390SDan Williams } 4516f231ddaSDan Williams 452858d4aa7SDave Jiang return 0; 4536f231ddaSDan Williams } 454