18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * PMC-Sierra PM8001/8081/8088/8089 SAS/SATA based host adapters driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2008-2009 USI Co., Ltd. 58c2ecf20Sopenharmony_ci * All rights reserved. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 88c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 98c2ecf20Sopenharmony_ci * are met: 108c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 118c2ecf20Sopenharmony_ci * notice, this list of conditions, and the following disclaimer, 128c2ecf20Sopenharmony_ci * without modification. 138c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce at minimum a disclaimer 148c2ecf20Sopenharmony_ci * substantially similar to the "NO WARRANTY" disclaimer below 158c2ecf20Sopenharmony_ci * ("Disclaimer") and any redistribution must be conditioned upon 168c2ecf20Sopenharmony_ci * including a substantially similar Disclaimer requirement for further 178c2ecf20Sopenharmony_ci * binary redistribution. 188c2ecf20Sopenharmony_ci * 3. Neither the names of the above-listed copyright holders nor the names 198c2ecf20Sopenharmony_ci * of any contributors may be used to endorse or promote products derived 208c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 238c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free 248c2ecf20Sopenharmony_ci * Software Foundation. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * NO WARRANTY 278c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 288c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 298c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 308c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 318c2ecf20Sopenharmony_ci * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 328c2ecf20Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 338c2ecf20Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 348c2ecf20Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 358c2ecf20Sopenharmony_ci * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 368c2ecf20Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 378c2ecf20Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGES. 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include <linux/slab.h> 428c2ecf20Sopenharmony_ci#include "pm8001_sas.h" 438c2ecf20Sopenharmony_ci#include "pm8001_chips.h" 448c2ecf20Sopenharmony_ci#include "pm80xx_hwi.h" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic ulong logging_level = PM8001_FAIL_LOGGING | PM8001_IOERR_LOGGING; 478c2ecf20Sopenharmony_cimodule_param(logging_level, ulong, 0644); 488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(logging_level, " bits for enabling logging info."); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic ulong link_rate = LINKRATE_15 | LINKRATE_30 | LINKRATE_60 | LINKRATE_120; 518c2ecf20Sopenharmony_cimodule_param(link_rate, ulong, 0644); 528c2ecf20Sopenharmony_ciMODULE_PARM_DESC(link_rate, "Enable link rate.\n" 538c2ecf20Sopenharmony_ci " 1: Link rate 1.5G\n" 548c2ecf20Sopenharmony_ci " 2: Link rate 3.0G\n" 558c2ecf20Sopenharmony_ci " 4: Link rate 6.0G\n" 568c2ecf20Sopenharmony_ci " 8: Link rate 12.0G\n"); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic struct scsi_transport_template *pm8001_stt; 598c2ecf20Sopenharmony_cistatic int pm8001_init_ccb_tag(struct pm8001_hba_info *, struct Scsi_Host *, struct pci_dev *); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * chip info structure to identify chip key functionality as 638c2ecf20Sopenharmony_ci * encryption available/not, no of ports, hw specific function ref 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_cistatic const struct pm8001_chip_info pm8001_chips[] = { 668c2ecf20Sopenharmony_ci [chip_8001] = {0, 8, &pm8001_8001_dispatch,}, 678c2ecf20Sopenharmony_ci [chip_8008] = {0, 8, &pm8001_80xx_dispatch,}, 688c2ecf20Sopenharmony_ci [chip_8009] = {1, 8, &pm8001_80xx_dispatch,}, 698c2ecf20Sopenharmony_ci [chip_8018] = {0, 16, &pm8001_80xx_dispatch,}, 708c2ecf20Sopenharmony_ci [chip_8019] = {1, 16, &pm8001_80xx_dispatch,}, 718c2ecf20Sopenharmony_ci [chip_8074] = {0, 8, &pm8001_80xx_dispatch,}, 728c2ecf20Sopenharmony_ci [chip_8076] = {0, 16, &pm8001_80xx_dispatch,}, 738c2ecf20Sopenharmony_ci [chip_8077] = {0, 16, &pm8001_80xx_dispatch,}, 748c2ecf20Sopenharmony_ci [chip_8006] = {0, 16, &pm8001_80xx_dispatch,}, 758c2ecf20Sopenharmony_ci [chip_8070] = {0, 8, &pm8001_80xx_dispatch,}, 768c2ecf20Sopenharmony_ci [chip_8072] = {0, 16, &pm8001_80xx_dispatch,}, 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_cistatic int pm8001_id; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciLIST_HEAD(hba_list); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistruct workqueue_struct *pm8001_wq; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* 858c2ecf20Sopenharmony_ci * The main structure which LLDD must register for scsi core. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_cistatic struct scsi_host_template pm8001_sht = { 888c2ecf20Sopenharmony_ci .module = THIS_MODULE, 898c2ecf20Sopenharmony_ci .name = DRV_NAME, 908c2ecf20Sopenharmony_ci .queuecommand = sas_queuecommand, 918c2ecf20Sopenharmony_ci .dma_need_drain = ata_scsi_dma_need_drain, 928c2ecf20Sopenharmony_ci .target_alloc = sas_target_alloc, 938c2ecf20Sopenharmony_ci .slave_configure = sas_slave_configure, 948c2ecf20Sopenharmony_ci .scan_finished = pm8001_scan_finished, 958c2ecf20Sopenharmony_ci .scan_start = pm8001_scan_start, 968c2ecf20Sopenharmony_ci .change_queue_depth = sas_change_queue_depth, 978c2ecf20Sopenharmony_ci .bios_param = sas_bios_param, 988c2ecf20Sopenharmony_ci .can_queue = 1, 998c2ecf20Sopenharmony_ci .this_id = -1, 1008c2ecf20Sopenharmony_ci .sg_tablesize = PM8001_MAX_DMA_SG, 1018c2ecf20Sopenharmony_ci .max_sectors = SCSI_DEFAULT_MAX_SECTORS, 1028c2ecf20Sopenharmony_ci .eh_device_reset_handler = sas_eh_device_reset_handler, 1038c2ecf20Sopenharmony_ci .eh_target_reset_handler = sas_eh_target_reset_handler, 1048c2ecf20Sopenharmony_ci .slave_alloc = sas_slave_alloc, 1058c2ecf20Sopenharmony_ci .target_destroy = sas_target_destroy, 1068c2ecf20Sopenharmony_ci .ioctl = sas_ioctl, 1078c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 1088c2ecf20Sopenharmony_ci .compat_ioctl = sas_ioctl, 1098c2ecf20Sopenharmony_ci#endif 1108c2ecf20Sopenharmony_ci .shost_attrs = pm8001_host_attrs, 1118c2ecf20Sopenharmony_ci .track_queue_depth = 1, 1128c2ecf20Sopenharmony_ci}; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* 1158c2ecf20Sopenharmony_ci * Sas layer call this function to execute specific task. 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_cistatic struct sas_domain_function_template pm8001_transport_ops = { 1188c2ecf20Sopenharmony_ci .lldd_dev_found = pm8001_dev_found, 1198c2ecf20Sopenharmony_ci .lldd_dev_gone = pm8001_dev_gone, 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci .lldd_execute_task = pm8001_queue_command, 1228c2ecf20Sopenharmony_ci .lldd_control_phy = pm8001_phy_control, 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci .lldd_abort_task = pm8001_abort_task, 1258c2ecf20Sopenharmony_ci .lldd_abort_task_set = pm8001_abort_task_set, 1268c2ecf20Sopenharmony_ci .lldd_clear_aca = pm8001_clear_aca, 1278c2ecf20Sopenharmony_ci .lldd_clear_task_set = pm8001_clear_task_set, 1288c2ecf20Sopenharmony_ci .lldd_I_T_nexus_reset = pm8001_I_T_nexus_reset, 1298c2ecf20Sopenharmony_ci .lldd_lu_reset = pm8001_lu_reset, 1308c2ecf20Sopenharmony_ci .lldd_query_task = pm8001_query_task, 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/** 1348c2ecf20Sopenharmony_ci * pm8001_phy_init - initiate our adapter phys 1358c2ecf20Sopenharmony_ci * @pm8001_ha: our hba structure. 1368c2ecf20Sopenharmony_ci * @phy_id: phy id. 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_cistatic void pm8001_phy_init(struct pm8001_hba_info *pm8001_ha, int phy_id) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; 1418c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy = &phy->sas_phy; 1428c2ecf20Sopenharmony_ci phy->phy_state = PHY_LINK_DISABLE; 1438c2ecf20Sopenharmony_ci phy->pm8001_ha = pm8001_ha; 1448c2ecf20Sopenharmony_ci sas_phy->enabled = (phy_id < pm8001_ha->chip->n_phy) ? 1 : 0; 1458c2ecf20Sopenharmony_ci sas_phy->class = SAS; 1468c2ecf20Sopenharmony_ci sas_phy->iproto = SAS_PROTOCOL_ALL; 1478c2ecf20Sopenharmony_ci sas_phy->tproto = 0; 1488c2ecf20Sopenharmony_ci sas_phy->type = PHY_TYPE_PHYSICAL; 1498c2ecf20Sopenharmony_ci sas_phy->role = PHY_ROLE_INITIATOR; 1508c2ecf20Sopenharmony_ci sas_phy->oob_mode = OOB_NOT_CONNECTED; 1518c2ecf20Sopenharmony_ci sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN; 1528c2ecf20Sopenharmony_ci sas_phy->id = phy_id; 1538c2ecf20Sopenharmony_ci sas_phy->sas_addr = (u8 *)&phy->dev_sas_addr; 1548c2ecf20Sopenharmony_ci sas_phy->frame_rcvd = &phy->frame_rcvd[0]; 1558c2ecf20Sopenharmony_ci sas_phy->ha = (struct sas_ha_struct *)pm8001_ha->shost->hostdata; 1568c2ecf20Sopenharmony_ci sas_phy->lldd_phy = phy; 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/** 1608c2ecf20Sopenharmony_ci * pm8001_free - free hba 1618c2ecf20Sopenharmony_ci * @pm8001_ha: our hba structure. 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_cistatic void pm8001_free(struct pm8001_hba_info *pm8001_ha) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci int i; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (!pm8001_ha) 1688c2ecf20Sopenharmony_ci return; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci for (i = 0; i < USI_MAX_MEMCNT; i++) { 1718c2ecf20Sopenharmony_ci if (pm8001_ha->memoryMap.region[i].virt_ptr != NULL) { 1728c2ecf20Sopenharmony_ci dma_free_coherent(&pm8001_ha->pdev->dev, 1738c2ecf20Sopenharmony_ci (pm8001_ha->memoryMap.region[i].total_len + 1748c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[i].alignment), 1758c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[i].virt_ptr, 1768c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[i].phys_addr); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci PM8001_CHIP_DISP->chip_iounmap(pm8001_ha); 1808c2ecf20Sopenharmony_ci flush_workqueue(pm8001_wq); 1818c2ecf20Sopenharmony_ci kfree(pm8001_ha->tags); 1828c2ecf20Sopenharmony_ci kfree(pm8001_ha); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci#ifdef PM8001_USE_TASKLET 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/** 1888c2ecf20Sopenharmony_ci * tasklet for 64 msi-x interrupt handler 1898c2ecf20Sopenharmony_ci * @opaque: the passed general host adapter struct 1908c2ecf20Sopenharmony_ci * Note: pm8001_tasklet is common for pm8001 & pm80xx 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_cistatic void pm8001_tasklet(unsigned long opaque) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha; 1958c2ecf20Sopenharmony_ci struct isr_param *irq_vector; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci irq_vector = (struct isr_param *)opaque; 1988c2ecf20Sopenharmony_ci pm8001_ha = irq_vector->drv_inst; 1998c2ecf20Sopenharmony_ci if (unlikely(!pm8001_ha)) 2008c2ecf20Sopenharmony_ci BUG_ON(1); 2018c2ecf20Sopenharmony_ci PM8001_CHIP_DISP->isr(pm8001_ha, irq_vector->irq_id); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci#endif 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/** 2068c2ecf20Sopenharmony_ci * pm8001_interrupt_handler_msix - main MSIX interrupt handler. 2078c2ecf20Sopenharmony_ci * It obtains the vector number and calls the equivalent bottom 2088c2ecf20Sopenharmony_ci * half or services directly. 2098c2ecf20Sopenharmony_ci * @irq: interrupt number 2108c2ecf20Sopenharmony_ci * @opaque: the passed outbound queue/vector. Host structure is 2118c2ecf20Sopenharmony_ci * retrieved from the same. 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_cistatic irqreturn_t pm8001_interrupt_handler_msix(int irq, void *opaque) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct isr_param *irq_vector; 2168c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha; 2178c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_HANDLED; 2188c2ecf20Sopenharmony_ci irq_vector = (struct isr_param *)opaque; 2198c2ecf20Sopenharmony_ci pm8001_ha = irq_vector->drv_inst; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (unlikely(!pm8001_ha)) 2228c2ecf20Sopenharmony_ci return IRQ_NONE; 2238c2ecf20Sopenharmony_ci if (!PM8001_CHIP_DISP->is_our_interrupt(pm8001_ha)) 2248c2ecf20Sopenharmony_ci return IRQ_NONE; 2258c2ecf20Sopenharmony_ci#ifdef PM8001_USE_TASKLET 2268c2ecf20Sopenharmony_ci tasklet_schedule(&pm8001_ha->tasklet[irq_vector->irq_id]); 2278c2ecf20Sopenharmony_ci#else 2288c2ecf20Sopenharmony_ci ret = PM8001_CHIP_DISP->isr(pm8001_ha, irq_vector->irq_id); 2298c2ecf20Sopenharmony_ci#endif 2308c2ecf20Sopenharmony_ci return ret; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci/** 2348c2ecf20Sopenharmony_ci * pm8001_interrupt_handler_intx - main INTx interrupt handler. 2358c2ecf20Sopenharmony_ci * @irq: interrupt number 2368c2ecf20Sopenharmony_ci * @dev_id: sas_ha structure. The HBA is retrieved from sas_has structure. 2378c2ecf20Sopenharmony_ci */ 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic irqreturn_t pm8001_interrupt_handler_intx(int irq, void *dev_id) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha; 2428c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_HANDLED; 2438c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = dev_id; 2448c2ecf20Sopenharmony_ci pm8001_ha = sha->lldd_ha; 2458c2ecf20Sopenharmony_ci if (unlikely(!pm8001_ha)) 2468c2ecf20Sopenharmony_ci return IRQ_NONE; 2478c2ecf20Sopenharmony_ci if (!PM8001_CHIP_DISP->is_our_interrupt(pm8001_ha)) 2488c2ecf20Sopenharmony_ci return IRQ_NONE; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci#ifdef PM8001_USE_TASKLET 2518c2ecf20Sopenharmony_ci tasklet_schedule(&pm8001_ha->tasklet[0]); 2528c2ecf20Sopenharmony_ci#else 2538c2ecf20Sopenharmony_ci ret = PM8001_CHIP_DISP->isr(pm8001_ha, 0); 2548c2ecf20Sopenharmony_ci#endif 2558c2ecf20Sopenharmony_ci return ret; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci/** 2618c2ecf20Sopenharmony_ci * pm8001_alloc - initiate our hba structure and 6 DMAs area. 2628c2ecf20Sopenharmony_ci * @pm8001_ha: our hba structure. 2638c2ecf20Sopenharmony_ci * @ent: PCI device ID structure to match on 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_cistatic int pm8001_alloc(struct pm8001_hba_info *pm8001_ha, 2668c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci int i, count = 0, rc = 0; 2698c2ecf20Sopenharmony_ci u32 ci_offset, ib_offset, ob_offset, pi_offset; 2708c2ecf20Sopenharmony_ci struct inbound_queue_table *circularQ; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci spin_lock_init(&pm8001_ha->lock); 2738c2ecf20Sopenharmony_ci spin_lock_init(&pm8001_ha->bitmap_lock); 2748c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "pm8001_alloc: PHY:%x\n", 2758c2ecf20Sopenharmony_ci pm8001_ha->chip->n_phy); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* Request Interrupt */ 2788c2ecf20Sopenharmony_ci rc = pm8001_request_irq(pm8001_ha); 2798c2ecf20Sopenharmony_ci if (rc) 2808c2ecf20Sopenharmony_ci goto err_out; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci count = pm8001_ha->max_q_num; 2838c2ecf20Sopenharmony_ci /* Queues are chosen based on the number of cores/msix availability */ 2848c2ecf20Sopenharmony_ci ib_offset = pm8001_ha->ib_offset = USI_MAX_MEMCNT_BASE; 2858c2ecf20Sopenharmony_ci ci_offset = pm8001_ha->ci_offset = ib_offset + count; 2868c2ecf20Sopenharmony_ci ob_offset = pm8001_ha->ob_offset = ci_offset + count; 2878c2ecf20Sopenharmony_ci pi_offset = pm8001_ha->pi_offset = ob_offset + count; 2888c2ecf20Sopenharmony_ci pm8001_ha->max_memcnt = pi_offset + count; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->chip->n_phy; i++) { 2918c2ecf20Sopenharmony_ci pm8001_phy_init(pm8001_ha, i); 2928c2ecf20Sopenharmony_ci pm8001_ha->port[i].wide_port_phymap = 0; 2938c2ecf20Sopenharmony_ci pm8001_ha->port[i].port_attached = 0; 2948c2ecf20Sopenharmony_ci pm8001_ha->port[i].port_state = 0; 2958c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pm8001_ha->port[i].list); 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* MPI Memory region 1 for AAP Event Log for fw */ 2998c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[AAP1].num_elements = 1; 3008c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[AAP1].element_size = PM8001_EVENT_LOG_SIZE; 3018c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[AAP1].total_len = PM8001_EVENT_LOG_SIZE; 3028c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[AAP1].alignment = 32; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* MPI Memory region 2 for IOP Event Log for fw */ 3058c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[IOP].num_elements = 1; 3068c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[IOP].element_size = PM8001_EVENT_LOG_SIZE; 3078c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[IOP].total_len = PM8001_EVENT_LOG_SIZE; 3088c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[IOP].alignment = 32; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 3118c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->inbnd_q_tbl[i]; 3128c2ecf20Sopenharmony_ci spin_lock_init(&circularQ->iq_lock); 3138c2ecf20Sopenharmony_ci /* MPI Memory region 3 for consumer Index of inbound queues */ 3148c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ci_offset+i].num_elements = 1; 3158c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ci_offset+i].element_size = 4; 3168c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ci_offset+i].total_len = 4; 3178c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ci_offset+i].alignment = 4; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if ((ent->driver_data) != chip_8001) { 3208c2ecf20Sopenharmony_ci /* MPI Memory region 5 inbound queues */ 3218c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ib_offset+i].num_elements = 3228c2ecf20Sopenharmony_ci PM8001_MPI_QUEUE; 3238c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ib_offset+i].element_size 3248c2ecf20Sopenharmony_ci = 128; 3258c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ib_offset+i].total_len = 3268c2ecf20Sopenharmony_ci PM8001_MPI_QUEUE * 128; 3278c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ib_offset+i].alignment 3288c2ecf20Sopenharmony_ci = 128; 3298c2ecf20Sopenharmony_ci } else { 3308c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ib_offset+i].num_elements = 3318c2ecf20Sopenharmony_ci PM8001_MPI_QUEUE; 3328c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ib_offset+i].element_size 3338c2ecf20Sopenharmony_ci = 64; 3348c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ib_offset+i].total_len = 3358c2ecf20Sopenharmony_ci PM8001_MPI_QUEUE * 64; 3368c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ib_offset+i].alignment = 64; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 3418c2ecf20Sopenharmony_ci /* MPI Memory region 4 for producer Index of outbound queues */ 3428c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[pi_offset+i].num_elements = 1; 3438c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[pi_offset+i].element_size = 4; 3448c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[pi_offset+i].total_len = 4; 3458c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[pi_offset+i].alignment = 4; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (ent->driver_data != chip_8001) { 3488c2ecf20Sopenharmony_ci /* MPI Memory region 6 Outbound queues */ 3498c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ob_offset+i].num_elements = 3508c2ecf20Sopenharmony_ci PM8001_MPI_QUEUE; 3518c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ob_offset+i].element_size 3528c2ecf20Sopenharmony_ci = 128; 3538c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ob_offset+i].total_len = 3548c2ecf20Sopenharmony_ci PM8001_MPI_QUEUE * 128; 3558c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ob_offset+i].alignment 3568c2ecf20Sopenharmony_ci = 128; 3578c2ecf20Sopenharmony_ci } else { 3588c2ecf20Sopenharmony_ci /* MPI Memory region 6 Outbound queues */ 3598c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ob_offset+i].num_elements = 3608c2ecf20Sopenharmony_ci PM8001_MPI_QUEUE; 3618c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ob_offset+i].element_size 3628c2ecf20Sopenharmony_ci = 64; 3638c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ob_offset+i].total_len = 3648c2ecf20Sopenharmony_ci PM8001_MPI_QUEUE * 64; 3658c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ob_offset+i].alignment = 64; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci /* Memory region write DMA*/ 3708c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[NVMD].num_elements = 1; 3718c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[NVMD].element_size = 4096; 3728c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[NVMD].total_len = 4096; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* Memory region for fw flash */ 3758c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[FW_FLASH].total_len = 4096; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[FORENSIC_MEM].num_elements = 1; 3788c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[FORENSIC_MEM].total_len = 0x10000; 3798c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[FORENSIC_MEM].element_size = 0x10000; 3808c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[FORENSIC_MEM].alignment = 0x10000; 3818c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->max_memcnt; i++) { 3828c2ecf20Sopenharmony_ci if (pm8001_mem_alloc(pm8001_ha->pdev, 3838c2ecf20Sopenharmony_ci &pm8001_ha->memoryMap.region[i].virt_ptr, 3848c2ecf20Sopenharmony_ci &pm8001_ha->memoryMap.region[i].phys_addr, 3858c2ecf20Sopenharmony_ci &pm8001_ha->memoryMap.region[i].phys_addr_hi, 3868c2ecf20Sopenharmony_ci &pm8001_ha->memoryMap.region[i].phys_addr_lo, 3878c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[i].total_len, 3888c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[i].alignment) != 0) { 3898c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 3908c2ecf20Sopenharmony_ci "Mem%d alloc failed\n", 3918c2ecf20Sopenharmony_ci i); 3928c2ecf20Sopenharmony_ci goto err_out; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci /* Memory region for devices*/ 3978c2ecf20Sopenharmony_ci pm8001_ha->devices = kzalloc(PM8001_MAX_DEVICES 3988c2ecf20Sopenharmony_ci * sizeof(struct pm8001_device), GFP_KERNEL); 3998c2ecf20Sopenharmony_ci if (!pm8001_ha->devices) { 4008c2ecf20Sopenharmony_ci rc = -ENOMEM; 4018c2ecf20Sopenharmony_ci goto err_out_nodev; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci for (i = 0; i < PM8001_MAX_DEVICES; i++) { 4048c2ecf20Sopenharmony_ci pm8001_ha->devices[i].dev_type = SAS_PHY_UNUSED; 4058c2ecf20Sopenharmony_ci pm8001_ha->devices[i].id = i; 4068c2ecf20Sopenharmony_ci pm8001_ha->devices[i].device_id = PM8001_MAX_DEVICES; 4078c2ecf20Sopenharmony_ci atomic_set(&pm8001_ha->devices[i].running_req, 0); 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci pm8001_ha->flags = PM8001F_INIT_TIME; 4108c2ecf20Sopenharmony_ci /* Initialize tags */ 4118c2ecf20Sopenharmony_ci pm8001_tag_init(pm8001_ha); 4128c2ecf20Sopenharmony_ci return 0; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cierr_out_nodev: 4158c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->max_memcnt; i++) { 4168c2ecf20Sopenharmony_ci if (pm8001_ha->memoryMap.region[i].virt_ptr != NULL) { 4178c2ecf20Sopenharmony_ci pci_free_consistent(pm8001_ha->pdev, 4188c2ecf20Sopenharmony_ci (pm8001_ha->memoryMap.region[i].total_len + 4198c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[i].alignment), 4208c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[i].virt_ptr, 4218c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[i].phys_addr); 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_cierr_out: 4258c2ecf20Sopenharmony_ci return 1; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci/** 4298c2ecf20Sopenharmony_ci * pm8001_ioremap - remap the pci high physical address to kernal virtual 4308c2ecf20Sopenharmony_ci * address so that we can access them. 4318c2ecf20Sopenharmony_ci * @pm8001_ha:our hba structure. 4328c2ecf20Sopenharmony_ci */ 4338c2ecf20Sopenharmony_cistatic int pm8001_ioremap(struct pm8001_hba_info *pm8001_ha) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci u32 bar; 4368c2ecf20Sopenharmony_ci u32 logicalBar = 0; 4378c2ecf20Sopenharmony_ci struct pci_dev *pdev; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci pdev = pm8001_ha->pdev; 4408c2ecf20Sopenharmony_ci /* map pci mem (PMC pci base 0-3)*/ 4418c2ecf20Sopenharmony_ci for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) { 4428c2ecf20Sopenharmony_ci /* 4438c2ecf20Sopenharmony_ci ** logical BARs for SPC: 4448c2ecf20Sopenharmony_ci ** bar 0 and 1 - logical BAR0 4458c2ecf20Sopenharmony_ci ** bar 2 and 3 - logical BAR1 4468c2ecf20Sopenharmony_ci ** bar4 - logical BAR2 4478c2ecf20Sopenharmony_ci ** bar5 - logical BAR3 4488c2ecf20Sopenharmony_ci ** Skip the appropriate assignments: 4498c2ecf20Sopenharmony_ci */ 4508c2ecf20Sopenharmony_ci if ((bar == 1) || (bar == 3)) 4518c2ecf20Sopenharmony_ci continue; 4528c2ecf20Sopenharmony_ci if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) { 4538c2ecf20Sopenharmony_ci pm8001_ha->io_mem[logicalBar].membase = 4548c2ecf20Sopenharmony_ci pci_resource_start(pdev, bar); 4558c2ecf20Sopenharmony_ci pm8001_ha->io_mem[logicalBar].memsize = 4568c2ecf20Sopenharmony_ci pci_resource_len(pdev, bar); 4578c2ecf20Sopenharmony_ci pm8001_ha->io_mem[logicalBar].memvirtaddr = 4588c2ecf20Sopenharmony_ci ioremap(pm8001_ha->io_mem[logicalBar].membase, 4598c2ecf20Sopenharmony_ci pm8001_ha->io_mem[logicalBar].memsize); 4608c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, 4618c2ecf20Sopenharmony_ci "PCI: bar %d, logicalBar %d\n", 4628c2ecf20Sopenharmony_ci bar, logicalBar); 4638c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, 4648c2ecf20Sopenharmony_ci "base addr %llx virt_addr=%llx len=%d\n", 4658c2ecf20Sopenharmony_ci (u64)pm8001_ha->io_mem[logicalBar].membase, 4668c2ecf20Sopenharmony_ci (u64)(unsigned long) 4678c2ecf20Sopenharmony_ci pm8001_ha->io_mem[logicalBar].memvirtaddr, 4688c2ecf20Sopenharmony_ci pm8001_ha->io_mem[logicalBar].memsize); 4698c2ecf20Sopenharmony_ci } else { 4708c2ecf20Sopenharmony_ci pm8001_ha->io_mem[logicalBar].membase = 0; 4718c2ecf20Sopenharmony_ci pm8001_ha->io_mem[logicalBar].memsize = 0; 4728c2ecf20Sopenharmony_ci pm8001_ha->io_mem[logicalBar].memvirtaddr = NULL; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci logicalBar++; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci return 0; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci/** 4808c2ecf20Sopenharmony_ci * pm8001_pci_alloc - initialize our ha card structure 4818c2ecf20Sopenharmony_ci * @pdev: pci device. 4828c2ecf20Sopenharmony_ci * @ent: ent 4838c2ecf20Sopenharmony_ci * @shost: scsi host struct which has been initialized before. 4848c2ecf20Sopenharmony_ci */ 4858c2ecf20Sopenharmony_cistatic struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev, 4868c2ecf20Sopenharmony_ci const struct pci_device_id *ent, 4878c2ecf20Sopenharmony_ci struct Scsi_Host *shost) 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha; 4918c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 4928c2ecf20Sopenharmony_ci int j; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci pm8001_ha = sha->lldd_ha; 4958c2ecf20Sopenharmony_ci if (!pm8001_ha) 4968c2ecf20Sopenharmony_ci return NULL; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci pm8001_ha->pdev = pdev; 4998c2ecf20Sopenharmony_ci pm8001_ha->dev = &pdev->dev; 5008c2ecf20Sopenharmony_ci pm8001_ha->chip_id = ent->driver_data; 5018c2ecf20Sopenharmony_ci pm8001_ha->chip = &pm8001_chips[pm8001_ha->chip_id]; 5028c2ecf20Sopenharmony_ci pm8001_ha->irq = pdev->irq; 5038c2ecf20Sopenharmony_ci pm8001_ha->sas = sha; 5048c2ecf20Sopenharmony_ci pm8001_ha->shost = shost; 5058c2ecf20Sopenharmony_ci pm8001_ha->id = pm8001_id++; 5068c2ecf20Sopenharmony_ci pm8001_ha->logging_level = logging_level; 5078c2ecf20Sopenharmony_ci pm8001_ha->non_fatal_count = 0; 5088c2ecf20Sopenharmony_ci if (link_rate >= 1 && link_rate <= 15) 5098c2ecf20Sopenharmony_ci pm8001_ha->link_rate = (link_rate << 8); 5108c2ecf20Sopenharmony_ci else { 5118c2ecf20Sopenharmony_ci pm8001_ha->link_rate = LINKRATE_15 | LINKRATE_30 | 5128c2ecf20Sopenharmony_ci LINKRATE_60 | LINKRATE_120; 5138c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 5148c2ecf20Sopenharmony_ci "Setting link rate to default value\n"); 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci sprintf(pm8001_ha->name, "%s%d", DRV_NAME, pm8001_ha->id); 5178c2ecf20Sopenharmony_ci /* IOMB size is 128 for 8088/89 controllers */ 5188c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id != chip_8001) 5198c2ecf20Sopenharmony_ci pm8001_ha->iomb_size = IOMB_SIZE_SPCV; 5208c2ecf20Sopenharmony_ci else 5218c2ecf20Sopenharmony_ci pm8001_ha->iomb_size = IOMB_SIZE_SPC; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci#ifdef PM8001_USE_TASKLET 5248c2ecf20Sopenharmony_ci /* Tasklet for non msi-x interrupt handler */ 5258c2ecf20Sopenharmony_ci if ((!pdev->msix_cap || !pci_msi_enabled()) 5268c2ecf20Sopenharmony_ci || (pm8001_ha->chip_id == chip_8001)) 5278c2ecf20Sopenharmony_ci tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet, 5288c2ecf20Sopenharmony_ci (unsigned long)&(pm8001_ha->irq_vector[0])); 5298c2ecf20Sopenharmony_ci else 5308c2ecf20Sopenharmony_ci for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) 5318c2ecf20Sopenharmony_ci tasklet_init(&pm8001_ha->tasklet[j], pm8001_tasklet, 5328c2ecf20Sopenharmony_ci (unsigned long)&(pm8001_ha->irq_vector[j])); 5338c2ecf20Sopenharmony_ci#endif 5348c2ecf20Sopenharmony_ci pm8001_ioremap(pm8001_ha); 5358c2ecf20Sopenharmony_ci if (!pm8001_alloc(pm8001_ha, ent)) 5368c2ecf20Sopenharmony_ci return pm8001_ha; 5378c2ecf20Sopenharmony_ci pm8001_free(pm8001_ha); 5388c2ecf20Sopenharmony_ci return NULL; 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci/** 5428c2ecf20Sopenharmony_ci * pci_go_44 - pm8001 specified, its DMA is 44 bit rather than 64 bit 5438c2ecf20Sopenharmony_ci * @pdev: pci device. 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_cistatic int pci_go_44(struct pci_dev *pdev) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci int rc; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44)); 5508c2ecf20Sopenharmony_ci if (rc) { 5518c2ecf20Sopenharmony_ci rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 5528c2ecf20Sopenharmony_ci if (rc) 5538c2ecf20Sopenharmony_ci dev_printk(KERN_ERR, &pdev->dev, 5548c2ecf20Sopenharmony_ci "32-bit DMA enable failed\n"); 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci return rc; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci/** 5608c2ecf20Sopenharmony_ci * pm8001_prep_sas_ha_init - allocate memory in general hba struct && init them. 5618c2ecf20Sopenharmony_ci * @shost: scsi host which has been allocated outside. 5628c2ecf20Sopenharmony_ci * @chip_info: our ha struct. 5638c2ecf20Sopenharmony_ci */ 5648c2ecf20Sopenharmony_cistatic int pm8001_prep_sas_ha_init(struct Scsi_Host *shost, 5658c2ecf20Sopenharmony_ci const struct pm8001_chip_info *chip_info) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci int phy_nr, port_nr; 5688c2ecf20Sopenharmony_ci struct asd_sas_phy **arr_phy; 5698c2ecf20Sopenharmony_ci struct asd_sas_port **arr_port; 5708c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci phy_nr = chip_info->n_phy; 5738c2ecf20Sopenharmony_ci port_nr = phy_nr; 5748c2ecf20Sopenharmony_ci memset(sha, 0x00, sizeof(*sha)); 5758c2ecf20Sopenharmony_ci arr_phy = kcalloc(phy_nr, sizeof(void *), GFP_KERNEL); 5768c2ecf20Sopenharmony_ci if (!arr_phy) 5778c2ecf20Sopenharmony_ci goto exit; 5788c2ecf20Sopenharmony_ci arr_port = kcalloc(port_nr, sizeof(void *), GFP_KERNEL); 5798c2ecf20Sopenharmony_ci if (!arr_port) 5808c2ecf20Sopenharmony_ci goto exit_free2; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci sha->sas_phy = arr_phy; 5838c2ecf20Sopenharmony_ci sha->sas_port = arr_port; 5848c2ecf20Sopenharmony_ci sha->lldd_ha = kzalloc(sizeof(struct pm8001_hba_info), GFP_KERNEL); 5858c2ecf20Sopenharmony_ci if (!sha->lldd_ha) 5868c2ecf20Sopenharmony_ci goto exit_free1; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci shost->transportt = pm8001_stt; 5898c2ecf20Sopenharmony_ci shost->max_id = PM8001_MAX_DEVICES; 5908c2ecf20Sopenharmony_ci shost->max_lun = 8; 5918c2ecf20Sopenharmony_ci shost->max_channel = 0; 5928c2ecf20Sopenharmony_ci shost->unique_id = pm8001_id; 5938c2ecf20Sopenharmony_ci shost->max_cmd_len = 16; 5948c2ecf20Sopenharmony_ci shost->can_queue = PM8001_CAN_QUEUE; 5958c2ecf20Sopenharmony_ci shost->cmd_per_lun = 32; 5968c2ecf20Sopenharmony_ci return 0; 5978c2ecf20Sopenharmony_ciexit_free1: 5988c2ecf20Sopenharmony_ci kfree(arr_port); 5998c2ecf20Sopenharmony_ciexit_free2: 6008c2ecf20Sopenharmony_ci kfree(arr_phy); 6018c2ecf20Sopenharmony_ciexit: 6028c2ecf20Sopenharmony_ci return -1; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci/** 6068c2ecf20Sopenharmony_ci * pm8001_post_sas_ha_init - initialize general hba struct defined in libsas 6078c2ecf20Sopenharmony_ci * @shost: scsi host which has been allocated outside 6088c2ecf20Sopenharmony_ci * @chip_info: our ha struct. 6098c2ecf20Sopenharmony_ci */ 6108c2ecf20Sopenharmony_cistatic void pm8001_post_sas_ha_init(struct Scsi_Host *shost, 6118c2ecf20Sopenharmony_ci const struct pm8001_chip_info *chip_info) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci int i = 0; 6148c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha; 6158c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci pm8001_ha = sha->lldd_ha; 6188c2ecf20Sopenharmony_ci for (i = 0; i < chip_info->n_phy; i++) { 6198c2ecf20Sopenharmony_ci sha->sas_phy[i] = &pm8001_ha->phy[i].sas_phy; 6208c2ecf20Sopenharmony_ci sha->sas_port[i] = &pm8001_ha->port[i].sas_port; 6218c2ecf20Sopenharmony_ci sha->sas_phy[i]->sas_addr = 6228c2ecf20Sopenharmony_ci (u8 *)&pm8001_ha->phy[i].dev_sas_addr; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci sha->sas_ha_name = DRV_NAME; 6258c2ecf20Sopenharmony_ci sha->dev = pm8001_ha->dev; 6268c2ecf20Sopenharmony_ci sha->strict_wide_ports = 1; 6278c2ecf20Sopenharmony_ci sha->lldd_module = THIS_MODULE; 6288c2ecf20Sopenharmony_ci sha->sas_addr = &pm8001_ha->sas_addr[0]; 6298c2ecf20Sopenharmony_ci sha->num_phys = chip_info->n_phy; 6308c2ecf20Sopenharmony_ci sha->core.shost = shost; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci/** 6348c2ecf20Sopenharmony_ci * pm8001_init_sas_add - initialize sas address 6358c2ecf20Sopenharmony_ci * @pm8001_ha: our ha struct. 6368c2ecf20Sopenharmony_ci * 6378c2ecf20Sopenharmony_ci * Currently we just set the fixed SAS address to our HBA,for manufacture, 6388c2ecf20Sopenharmony_ci * it should read from the EEPROM 6398c2ecf20Sopenharmony_ci */ 6408c2ecf20Sopenharmony_cistatic void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci u8 i, j; 6438c2ecf20Sopenharmony_ci u8 sas_add[8]; 6448c2ecf20Sopenharmony_ci#ifdef PM8001_READ_VPD 6458c2ecf20Sopenharmony_ci /* For new SPC controllers WWN is stored in flash vpd 6468c2ecf20Sopenharmony_ci * For SPC/SPCve controllers WWN is stored in EEPROM 6478c2ecf20Sopenharmony_ci * For Older SPC WWN is stored in NVMD 6488c2ecf20Sopenharmony_ci */ 6498c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(completion); 6508c2ecf20Sopenharmony_ci struct pm8001_ioctl_payload payload; 6518c2ecf20Sopenharmony_ci u16 deviceid; 6528c2ecf20Sopenharmony_ci int rc; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid); 6558c2ecf20Sopenharmony_ci pm8001_ha->nvmd_completion = &completion; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id == chip_8001) { 6588c2ecf20Sopenharmony_ci if (deviceid == 0x8081 || deviceid == 0x0042) { 6598c2ecf20Sopenharmony_ci payload.minor_function = 4; 6608c2ecf20Sopenharmony_ci payload.rd_length = 4096; 6618c2ecf20Sopenharmony_ci } else { 6628c2ecf20Sopenharmony_ci payload.minor_function = 0; 6638c2ecf20Sopenharmony_ci payload.rd_length = 128; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci } else if ((pm8001_ha->chip_id == chip_8070 || 6668c2ecf20Sopenharmony_ci pm8001_ha->chip_id == chip_8072) && 6678c2ecf20Sopenharmony_ci pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ATTO) { 6688c2ecf20Sopenharmony_ci payload.minor_function = 4; 6698c2ecf20Sopenharmony_ci payload.rd_length = 4096; 6708c2ecf20Sopenharmony_ci } else { 6718c2ecf20Sopenharmony_ci payload.minor_function = 1; 6728c2ecf20Sopenharmony_ci payload.rd_length = 4096; 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci payload.offset = 0; 6758c2ecf20Sopenharmony_ci payload.func_specific = kzalloc(payload.rd_length, GFP_KERNEL); 6768c2ecf20Sopenharmony_ci if (!payload.func_specific) { 6778c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "mem alloc fail\n"); 6788c2ecf20Sopenharmony_ci return; 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci rc = PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload); 6818c2ecf20Sopenharmony_ci if (rc) { 6828c2ecf20Sopenharmony_ci kfree(payload.func_specific); 6838c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "nvmd failed\n"); 6848c2ecf20Sopenharmony_ci return; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci wait_for_completion(&completion); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci for (i = 0, j = 0; i <= 7; i++, j++) { 6898c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id == chip_8001) { 6908c2ecf20Sopenharmony_ci if (deviceid == 0x8081) 6918c2ecf20Sopenharmony_ci pm8001_ha->sas_addr[j] = 6928c2ecf20Sopenharmony_ci payload.func_specific[0x704 + i]; 6938c2ecf20Sopenharmony_ci else if (deviceid == 0x0042) 6948c2ecf20Sopenharmony_ci pm8001_ha->sas_addr[j] = 6958c2ecf20Sopenharmony_ci payload.func_specific[0x010 + i]; 6968c2ecf20Sopenharmony_ci } else if ((pm8001_ha->chip_id == chip_8070 || 6978c2ecf20Sopenharmony_ci pm8001_ha->chip_id == chip_8072) && 6988c2ecf20Sopenharmony_ci pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ATTO) { 6998c2ecf20Sopenharmony_ci pm8001_ha->sas_addr[j] = 7008c2ecf20Sopenharmony_ci payload.func_specific[0x010 + i]; 7018c2ecf20Sopenharmony_ci } else 7028c2ecf20Sopenharmony_ci pm8001_ha->sas_addr[j] = 7038c2ecf20Sopenharmony_ci payload.func_specific[0x804 + i]; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci memcpy(sas_add, pm8001_ha->sas_addr, SAS_ADDR_SIZE); 7068c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->chip->n_phy; i++) { 7078c2ecf20Sopenharmony_ci if (i && ((i % 4) == 0)) 7088c2ecf20Sopenharmony_ci sas_add[7] = sas_add[7] + 4; 7098c2ecf20Sopenharmony_ci memcpy(&pm8001_ha->phy[i].dev_sas_addr, 7108c2ecf20Sopenharmony_ci sas_add, SAS_ADDR_SIZE); 7118c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "phy %d sas_addr = %016llx\n", i, 7128c2ecf20Sopenharmony_ci pm8001_ha->phy[i].dev_sas_addr); 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci kfree(payload.func_specific); 7158c2ecf20Sopenharmony_ci#else 7168c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->chip->n_phy; i++) { 7178c2ecf20Sopenharmony_ci pm8001_ha->phy[i].dev_sas_addr = 0x50010c600047f9d0ULL; 7188c2ecf20Sopenharmony_ci pm8001_ha->phy[i].dev_sas_addr = 7198c2ecf20Sopenharmony_ci cpu_to_be64((u64) 7208c2ecf20Sopenharmony_ci (*(u64 *)&pm8001_ha->phy[i].dev_sas_addr)); 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci memcpy(pm8001_ha->sas_addr, &pm8001_ha->phy[0].dev_sas_addr, 7238c2ecf20Sopenharmony_ci SAS_ADDR_SIZE); 7248c2ecf20Sopenharmony_ci#endif 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci/* 7288c2ecf20Sopenharmony_ci * pm8001_get_phy_settings_info : Read phy setting values. 7298c2ecf20Sopenharmony_ci * @pm8001_ha : our hba. 7308c2ecf20Sopenharmony_ci */ 7318c2ecf20Sopenharmony_cistatic int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci#ifdef PM8001_READ_VPD 7358c2ecf20Sopenharmony_ci /*OPTION ROM FLASH read for the SPC cards */ 7368c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(completion); 7378c2ecf20Sopenharmony_ci struct pm8001_ioctl_payload payload; 7388c2ecf20Sopenharmony_ci int rc; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci pm8001_ha->nvmd_completion = &completion; 7418c2ecf20Sopenharmony_ci /* SAS ADDRESS read from flash / EEPROM */ 7428c2ecf20Sopenharmony_ci payload.minor_function = 6; 7438c2ecf20Sopenharmony_ci payload.offset = 0; 7448c2ecf20Sopenharmony_ci payload.rd_length = 4096; 7458c2ecf20Sopenharmony_ci payload.func_specific = kzalloc(4096, GFP_KERNEL); 7468c2ecf20Sopenharmony_ci if (!payload.func_specific) 7478c2ecf20Sopenharmony_ci return -ENOMEM; 7488c2ecf20Sopenharmony_ci /* Read phy setting values from flash */ 7498c2ecf20Sopenharmony_ci rc = PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload); 7508c2ecf20Sopenharmony_ci if (rc) { 7518c2ecf20Sopenharmony_ci kfree(payload.func_specific); 7528c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "nvmd failed\n"); 7538c2ecf20Sopenharmony_ci return -ENOMEM; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci wait_for_completion(&completion); 7568c2ecf20Sopenharmony_ci pm8001_set_phy_profile(pm8001_ha, sizeof(u8), payload.func_specific); 7578c2ecf20Sopenharmony_ci kfree(payload.func_specific); 7588c2ecf20Sopenharmony_ci#endif 7598c2ecf20Sopenharmony_ci return 0; 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistruct pm8001_mpi3_phy_pg_trx_config { 7638c2ecf20Sopenharmony_ci u32 LaneLosCfg; 7648c2ecf20Sopenharmony_ci u32 LanePgaCfg1; 7658c2ecf20Sopenharmony_ci u32 LanePisoCfg1; 7668c2ecf20Sopenharmony_ci u32 LanePisoCfg2; 7678c2ecf20Sopenharmony_ci u32 LanePisoCfg3; 7688c2ecf20Sopenharmony_ci u32 LanePisoCfg4; 7698c2ecf20Sopenharmony_ci u32 LanePisoCfg5; 7708c2ecf20Sopenharmony_ci u32 LanePisoCfg6; 7718c2ecf20Sopenharmony_ci u32 LaneBctCtrl; 7728c2ecf20Sopenharmony_ci}; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci/** 7758c2ecf20Sopenharmony_ci * pm8001_get_internal_phy_settings : Retrieves the internal PHY settings 7768c2ecf20Sopenharmony_ci * @pm8001_ha : our adapter 7778c2ecf20Sopenharmony_ci * @phycfg : PHY config page to populate 7788c2ecf20Sopenharmony_ci */ 7798c2ecf20Sopenharmony_cistatic 7808c2ecf20Sopenharmony_civoid pm8001_get_internal_phy_settings(struct pm8001_hba_info *pm8001_ha, 7818c2ecf20Sopenharmony_ci struct pm8001_mpi3_phy_pg_trx_config *phycfg) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci phycfg->LaneLosCfg = 0x00000132; 7848c2ecf20Sopenharmony_ci phycfg->LanePgaCfg1 = 0x00203949; 7858c2ecf20Sopenharmony_ci phycfg->LanePisoCfg1 = 0x000000FF; 7868c2ecf20Sopenharmony_ci phycfg->LanePisoCfg2 = 0xFF000001; 7878c2ecf20Sopenharmony_ci phycfg->LanePisoCfg3 = 0xE7011300; 7888c2ecf20Sopenharmony_ci phycfg->LanePisoCfg4 = 0x631C40C0; 7898c2ecf20Sopenharmony_ci phycfg->LanePisoCfg5 = 0xF8102036; 7908c2ecf20Sopenharmony_ci phycfg->LanePisoCfg6 = 0xF74A1000; 7918c2ecf20Sopenharmony_ci phycfg->LaneBctCtrl = 0x00FB33F8; 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci/** 7958c2ecf20Sopenharmony_ci * pm8001_get_external_phy_settings : Retrieves the external PHY settings 7968c2ecf20Sopenharmony_ci * @pm8001_ha : our adapter 7978c2ecf20Sopenharmony_ci * @phycfg : PHY config page to populate 7988c2ecf20Sopenharmony_ci */ 7998c2ecf20Sopenharmony_cistatic 8008c2ecf20Sopenharmony_civoid pm8001_get_external_phy_settings(struct pm8001_hba_info *pm8001_ha, 8018c2ecf20Sopenharmony_ci struct pm8001_mpi3_phy_pg_trx_config *phycfg) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci phycfg->LaneLosCfg = 0x00000132; 8048c2ecf20Sopenharmony_ci phycfg->LanePgaCfg1 = 0x00203949; 8058c2ecf20Sopenharmony_ci phycfg->LanePisoCfg1 = 0x000000FF; 8068c2ecf20Sopenharmony_ci phycfg->LanePisoCfg2 = 0xFF000001; 8078c2ecf20Sopenharmony_ci phycfg->LanePisoCfg3 = 0xE7011300; 8088c2ecf20Sopenharmony_ci phycfg->LanePisoCfg4 = 0x63349140; 8098c2ecf20Sopenharmony_ci phycfg->LanePisoCfg5 = 0xF8102036; 8108c2ecf20Sopenharmony_ci phycfg->LanePisoCfg6 = 0xF80D9300; 8118c2ecf20Sopenharmony_ci phycfg->LaneBctCtrl = 0x00FB33F8; 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci/** 8158c2ecf20Sopenharmony_ci * pm8001_get_phy_mask : Retrieves the mask that denotes if a PHY is int/ext 8168c2ecf20Sopenharmony_ci * @pm8001_ha : our adapter 8178c2ecf20Sopenharmony_ci * @phymask : The PHY mask 8188c2ecf20Sopenharmony_ci */ 8198c2ecf20Sopenharmony_cistatic 8208c2ecf20Sopenharmony_civoid pm8001_get_phy_mask(struct pm8001_hba_info *pm8001_ha, int *phymask) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci switch (pm8001_ha->pdev->subsystem_device) { 8238c2ecf20Sopenharmony_ci case 0x0070: /* H1280 - 8 external 0 internal */ 8248c2ecf20Sopenharmony_ci case 0x0072: /* H12F0 - 16 external 0 internal */ 8258c2ecf20Sopenharmony_ci *phymask = 0x0000; 8268c2ecf20Sopenharmony_ci break; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci case 0x0071: /* H1208 - 0 external 8 internal */ 8298c2ecf20Sopenharmony_ci case 0x0073: /* H120F - 0 external 16 internal */ 8308c2ecf20Sopenharmony_ci *phymask = 0xFFFF; 8318c2ecf20Sopenharmony_ci break; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci case 0x0080: /* H1244 - 4 external 4 internal */ 8348c2ecf20Sopenharmony_ci *phymask = 0x00F0; 8358c2ecf20Sopenharmony_ci break; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci case 0x0081: /* H1248 - 4 external 8 internal */ 8388c2ecf20Sopenharmony_ci *phymask = 0x0FF0; 8398c2ecf20Sopenharmony_ci break; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci case 0x0082: /* H1288 - 8 external 8 internal */ 8428c2ecf20Sopenharmony_ci *phymask = 0xFF00; 8438c2ecf20Sopenharmony_ci break; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci default: 8468c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, 8478c2ecf20Sopenharmony_ci "Unknown subsystem device=0x%.04x\n", 8488c2ecf20Sopenharmony_ci pm8001_ha->pdev->subsystem_device); 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci} 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci/** 8538c2ecf20Sopenharmony_ci * pm8001_set_phy_settings_ven_117c_12Gb : Configure ATTO 12Gb PHY settings 8548c2ecf20Sopenharmony_ci * @pm8001_ha : our adapter 8558c2ecf20Sopenharmony_ci */ 8568c2ecf20Sopenharmony_cistatic 8578c2ecf20Sopenharmony_ciint pm8001_set_phy_settings_ven_117c_12G(struct pm8001_hba_info *pm8001_ha) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci struct pm8001_mpi3_phy_pg_trx_config phycfg_int; 8608c2ecf20Sopenharmony_ci struct pm8001_mpi3_phy_pg_trx_config phycfg_ext; 8618c2ecf20Sopenharmony_ci int phymask = 0; 8628c2ecf20Sopenharmony_ci int i = 0; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci memset(&phycfg_int, 0, sizeof(phycfg_int)); 8658c2ecf20Sopenharmony_ci memset(&phycfg_ext, 0, sizeof(phycfg_ext)); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci pm8001_get_internal_phy_settings(pm8001_ha, &phycfg_int); 8688c2ecf20Sopenharmony_ci pm8001_get_external_phy_settings(pm8001_ha, &phycfg_ext); 8698c2ecf20Sopenharmony_ci pm8001_get_phy_mask(pm8001_ha, &phymask); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->chip->n_phy; i++) { 8728c2ecf20Sopenharmony_ci if (phymask & (1 << i)) {/* Internal PHY */ 8738c2ecf20Sopenharmony_ci pm8001_set_phy_profile_single(pm8001_ha, i, 8748c2ecf20Sopenharmony_ci sizeof(phycfg_int) / sizeof(u32), 8758c2ecf20Sopenharmony_ci (u32 *)&phycfg_int); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci } else { /* External PHY */ 8788c2ecf20Sopenharmony_ci pm8001_set_phy_profile_single(pm8001_ha, i, 8798c2ecf20Sopenharmony_ci sizeof(phycfg_ext) / sizeof(u32), 8808c2ecf20Sopenharmony_ci (u32 *)&phycfg_ext); 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci return 0; 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci/** 8888c2ecf20Sopenharmony_ci * pm8001_configure_phy_settings : Configures PHY settings based on vendor ID. 8898c2ecf20Sopenharmony_ci * @pm8001_ha : our hba. 8908c2ecf20Sopenharmony_ci */ 8918c2ecf20Sopenharmony_cistatic int pm8001_configure_phy_settings(struct pm8001_hba_info *pm8001_ha) 8928c2ecf20Sopenharmony_ci{ 8938c2ecf20Sopenharmony_ci switch (pm8001_ha->pdev->subsystem_vendor) { 8948c2ecf20Sopenharmony_ci case PCI_VENDOR_ID_ATTO: 8958c2ecf20Sopenharmony_ci if (pm8001_ha->pdev->device == 0x0042) /* 6Gb */ 8968c2ecf20Sopenharmony_ci return 0; 8978c2ecf20Sopenharmony_ci else 8988c2ecf20Sopenharmony_ci return pm8001_set_phy_settings_ven_117c_12G(pm8001_ha); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci case PCI_VENDOR_ID_ADAPTEC2: 9018c2ecf20Sopenharmony_ci case 0: 9028c2ecf20Sopenharmony_ci return 0; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci default: 9058c2ecf20Sopenharmony_ci return pm8001_get_phy_settings_info(pm8001_ha); 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci#ifdef PM8001_USE_MSIX 9108c2ecf20Sopenharmony_ci/** 9118c2ecf20Sopenharmony_ci * pm8001_setup_msix - enable MSI-X interrupt 9128c2ecf20Sopenharmony_ci * @pm8001_ha: our ha struct. 9138c2ecf20Sopenharmony_ci */ 9148c2ecf20Sopenharmony_cistatic u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci u32 number_of_intr; 9178c2ecf20Sopenharmony_ci int rc, cpu_online_count; 9188c2ecf20Sopenharmony_ci unsigned int allocated_irq_vectors; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci /* SPCv controllers supports 64 msi-x */ 9218c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id == chip_8001) { 9228c2ecf20Sopenharmony_ci number_of_intr = 1; 9238c2ecf20Sopenharmony_ci } else { 9248c2ecf20Sopenharmony_ci number_of_intr = PM8001_MAX_MSIX_VEC; 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci cpu_online_count = num_online_cpus(); 9288c2ecf20Sopenharmony_ci number_of_intr = min_t(int, cpu_online_count, number_of_intr); 9298c2ecf20Sopenharmony_ci rc = pci_alloc_irq_vectors(pm8001_ha->pdev, number_of_intr, 9308c2ecf20Sopenharmony_ci number_of_intr, PCI_IRQ_MSIX); 9318c2ecf20Sopenharmony_ci allocated_irq_vectors = rc; 9328c2ecf20Sopenharmony_ci if (rc < 0) 9338c2ecf20Sopenharmony_ci return rc; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci /* Assigns the number of interrupts */ 9368c2ecf20Sopenharmony_ci number_of_intr = min_t(int, allocated_irq_vectors, number_of_intr); 9378c2ecf20Sopenharmony_ci pm8001_ha->number_of_intr = number_of_intr; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci /* Maximum queue number updating in HBA structure */ 9408c2ecf20Sopenharmony_ci pm8001_ha->max_q_num = number_of_intr; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, 9438c2ecf20Sopenharmony_ci "pci_alloc_irq_vectors request ret:%d no of intr %d\n", 9448c2ecf20Sopenharmony_ci rc, pm8001_ha->number_of_intr); 9458c2ecf20Sopenharmony_ci return 0; 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic u32 pm8001_request_msix(struct pm8001_hba_info *pm8001_ha) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci u32 i = 0, j = 0; 9518c2ecf20Sopenharmony_ci int flag = 0, rc = 0; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id != chip_8001) 9548c2ecf20Sopenharmony_ci flag &= ~IRQF_SHARED; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, 9578c2ecf20Sopenharmony_ci "pci_enable_msix request number of intr %d\n", 9588c2ecf20Sopenharmony_ci pm8001_ha->number_of_intr); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->number_of_intr; i++) { 9618c2ecf20Sopenharmony_ci snprintf(pm8001_ha->intr_drvname[i], 9628c2ecf20Sopenharmony_ci sizeof(pm8001_ha->intr_drvname[0]), 9638c2ecf20Sopenharmony_ci "%s-%d", pm8001_ha->name, i); 9648c2ecf20Sopenharmony_ci pm8001_ha->irq_vector[i].irq_id = i; 9658c2ecf20Sopenharmony_ci pm8001_ha->irq_vector[i].drv_inst = pm8001_ha; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci rc = request_irq(pci_irq_vector(pm8001_ha->pdev, i), 9688c2ecf20Sopenharmony_ci pm8001_interrupt_handler_msix, flag, 9698c2ecf20Sopenharmony_ci pm8001_ha->intr_drvname[i], 9708c2ecf20Sopenharmony_ci &(pm8001_ha->irq_vector[i])); 9718c2ecf20Sopenharmony_ci if (rc) { 9728c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) { 9738c2ecf20Sopenharmony_ci free_irq(pci_irq_vector(pm8001_ha->pdev, i), 9748c2ecf20Sopenharmony_ci &(pm8001_ha->irq_vector[i])); 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci pci_free_irq_vectors(pm8001_ha->pdev); 9778c2ecf20Sopenharmony_ci break; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci return rc; 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci#endif 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci/** 9868c2ecf20Sopenharmony_ci * pm8001_request_irq - register interrupt 9878c2ecf20Sopenharmony_ci * @pm8001_ha: our ha struct. 9888c2ecf20Sopenharmony_ci */ 9898c2ecf20Sopenharmony_cistatic u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) 9908c2ecf20Sopenharmony_ci{ 9918c2ecf20Sopenharmony_ci struct pci_dev *pdev = pm8001_ha->pdev; 9928c2ecf20Sopenharmony_ci#ifdef PM8001_USE_MSIX 9938c2ecf20Sopenharmony_ci int rc; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) { 9968c2ecf20Sopenharmony_ci rc = pm8001_setup_msix(pm8001_ha); 9978c2ecf20Sopenharmony_ci if (rc) { 9988c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 9998c2ecf20Sopenharmony_ci "pm8001_setup_irq failed [ret: %d]\n", rc); 10008c2ecf20Sopenharmony_ci return rc; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci if (pdev->msix_cap && pci_msi_enabled()) 10048c2ecf20Sopenharmony_ci return pm8001_request_msix(pm8001_ha); 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "MSIX not supported!!!\n"); 10088c2ecf20Sopenharmony_ci#endif 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci /* initialize the INT-X interrupt */ 10118c2ecf20Sopenharmony_ci pm8001_ha->irq_vector[0].irq_id = 0; 10128c2ecf20Sopenharmony_ci pm8001_ha->irq_vector[0].drv_inst = pm8001_ha; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci return request_irq(pdev->irq, pm8001_interrupt_handler_intx, 10158c2ecf20Sopenharmony_ci IRQF_SHARED, pm8001_ha->name, 10168c2ecf20Sopenharmony_ci SHOST_TO_SAS_HA(pm8001_ha->shost)); 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci/** 10208c2ecf20Sopenharmony_ci * pm8001_pci_probe - probe supported device 10218c2ecf20Sopenharmony_ci * @pdev: pci device which kernel has been prepared for. 10228c2ecf20Sopenharmony_ci * @ent: pci device id 10238c2ecf20Sopenharmony_ci * 10248c2ecf20Sopenharmony_ci * This function is the main initialization function, when register a new 10258c2ecf20Sopenharmony_ci * pci driver it is invoked, all struct an hardware initilization should be done 10268c2ecf20Sopenharmony_ci * here, also, register interrupt 10278c2ecf20Sopenharmony_ci */ 10288c2ecf20Sopenharmony_cistatic int pm8001_pci_probe(struct pci_dev *pdev, 10298c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 10308c2ecf20Sopenharmony_ci{ 10318c2ecf20Sopenharmony_ci unsigned int rc; 10328c2ecf20Sopenharmony_ci u32 pci_reg; 10338c2ecf20Sopenharmony_ci u8 i = 0; 10348c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha; 10358c2ecf20Sopenharmony_ci struct Scsi_Host *shost = NULL; 10368c2ecf20Sopenharmony_ci const struct pm8001_chip_info *chip; 10378c2ecf20Sopenharmony_ci struct sas_ha_struct *sha; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci dev_printk(KERN_INFO, &pdev->dev, 10408c2ecf20Sopenharmony_ci "pm80xx: driver version %s\n", DRV_VERSION); 10418c2ecf20Sopenharmony_ci rc = pci_enable_device(pdev); 10428c2ecf20Sopenharmony_ci if (rc) 10438c2ecf20Sopenharmony_ci goto err_out_enable; 10448c2ecf20Sopenharmony_ci pci_set_master(pdev); 10458c2ecf20Sopenharmony_ci /* 10468c2ecf20Sopenharmony_ci * Enable pci slot busmaster by setting pci command register. 10478c2ecf20Sopenharmony_ci * This is required by FW for Cyclone card. 10488c2ecf20Sopenharmony_ci */ 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, PCI_COMMAND, &pci_reg); 10518c2ecf20Sopenharmony_ci pci_reg |= 0x157; 10528c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, PCI_COMMAND, pci_reg); 10538c2ecf20Sopenharmony_ci rc = pci_request_regions(pdev, DRV_NAME); 10548c2ecf20Sopenharmony_ci if (rc) 10558c2ecf20Sopenharmony_ci goto err_out_disable; 10568c2ecf20Sopenharmony_ci rc = pci_go_44(pdev); 10578c2ecf20Sopenharmony_ci if (rc) 10588c2ecf20Sopenharmony_ci goto err_out_regions; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci shost = scsi_host_alloc(&pm8001_sht, sizeof(void *)); 10618c2ecf20Sopenharmony_ci if (!shost) { 10628c2ecf20Sopenharmony_ci rc = -ENOMEM; 10638c2ecf20Sopenharmony_ci goto err_out_regions; 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci chip = &pm8001_chips[ent->driver_data]; 10668c2ecf20Sopenharmony_ci sha = kzalloc(sizeof(struct sas_ha_struct), GFP_KERNEL); 10678c2ecf20Sopenharmony_ci if (!sha) { 10688c2ecf20Sopenharmony_ci rc = -ENOMEM; 10698c2ecf20Sopenharmony_ci goto err_out_free_host; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci SHOST_TO_SAS_HA(shost) = sha; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci rc = pm8001_prep_sas_ha_init(shost, chip); 10748c2ecf20Sopenharmony_ci if (rc) { 10758c2ecf20Sopenharmony_ci rc = -ENOMEM; 10768c2ecf20Sopenharmony_ci goto err_out_free; 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, SHOST_TO_SAS_HA(shost)); 10798c2ecf20Sopenharmony_ci /* ent->driver variable is used to differentiate between controllers */ 10808c2ecf20Sopenharmony_ci pm8001_ha = pm8001_pci_alloc(pdev, ent, shost); 10818c2ecf20Sopenharmony_ci if (!pm8001_ha) { 10828c2ecf20Sopenharmony_ci rc = -ENOMEM; 10838c2ecf20Sopenharmony_ci goto err_out_free; 10848c2ecf20Sopenharmony_ci } 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha); 10878c2ecf20Sopenharmony_ci rc = PM8001_CHIP_DISP->chip_init(pm8001_ha); 10888c2ecf20Sopenharmony_ci if (rc) { 10898c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 10908c2ecf20Sopenharmony_ci "chip_init failed [ret: %d]\n", rc); 10918c2ecf20Sopenharmony_ci goto err_out_ha_free; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci rc = pm8001_init_ccb_tag(pm8001_ha, shost, pdev); 10958c2ecf20Sopenharmony_ci if (rc) 10968c2ecf20Sopenharmony_ci goto err_out_enable; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci rc = scsi_add_host(shost, &pdev->dev); 10998c2ecf20Sopenharmony_ci if (rc) 11008c2ecf20Sopenharmony_ci goto err_out_ha_free; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, 0); 11038c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id != chip_8001) { 11048c2ecf20Sopenharmony_ci for (i = 1; i < pm8001_ha->number_of_intr; i++) 11058c2ecf20Sopenharmony_ci PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, i); 11068c2ecf20Sopenharmony_ci /* setup thermal configuration. */ 11078c2ecf20Sopenharmony_ci pm80xx_set_thermal_config(pm8001_ha); 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci pm8001_init_sas_add(pm8001_ha); 11118c2ecf20Sopenharmony_ci /* phy setting support for motherboard controller */ 11128c2ecf20Sopenharmony_ci rc = pm8001_configure_phy_settings(pm8001_ha); 11138c2ecf20Sopenharmony_ci if (rc) 11148c2ecf20Sopenharmony_ci goto err_out_shost; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci pm8001_post_sas_ha_init(shost, chip); 11178c2ecf20Sopenharmony_ci rc = sas_register_ha(SHOST_TO_SAS_HA(shost)); 11188c2ecf20Sopenharmony_ci if (rc) { 11198c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 11208c2ecf20Sopenharmony_ci "sas_register_ha failed [ret: %d]\n", rc); 11218c2ecf20Sopenharmony_ci goto err_out_shost; 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci list_add_tail(&pm8001_ha->list, &hba_list); 11248c2ecf20Sopenharmony_ci pm8001_ha->flags = PM8001F_RUN_TIME; 11258c2ecf20Sopenharmony_ci scsi_scan_host(pm8001_ha->shost); 11268c2ecf20Sopenharmony_ci return 0; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_cierr_out_shost: 11298c2ecf20Sopenharmony_ci scsi_remove_host(pm8001_ha->shost); 11308c2ecf20Sopenharmony_cierr_out_ha_free: 11318c2ecf20Sopenharmony_ci pm8001_free(pm8001_ha); 11328c2ecf20Sopenharmony_cierr_out_free: 11338c2ecf20Sopenharmony_ci kfree(sha); 11348c2ecf20Sopenharmony_cierr_out_free_host: 11358c2ecf20Sopenharmony_ci scsi_host_put(shost); 11368c2ecf20Sopenharmony_cierr_out_regions: 11378c2ecf20Sopenharmony_ci pci_release_regions(pdev); 11388c2ecf20Sopenharmony_cierr_out_disable: 11398c2ecf20Sopenharmony_ci pci_disable_device(pdev); 11408c2ecf20Sopenharmony_cierr_out_enable: 11418c2ecf20Sopenharmony_ci return rc; 11428c2ecf20Sopenharmony_ci} 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci/* 11458c2ecf20Sopenharmony_ci * pm8001_init_ccb_tag - allocate memory to CCB and tag. 11468c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information. 11478c2ecf20Sopenharmony_ci * @shost: scsi host which has been allocated outside. 11488c2ecf20Sopenharmony_ci */ 11498c2ecf20Sopenharmony_cistatic int 11508c2ecf20Sopenharmony_cipm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha, struct Scsi_Host *shost, 11518c2ecf20Sopenharmony_ci struct pci_dev *pdev) 11528c2ecf20Sopenharmony_ci{ 11538c2ecf20Sopenharmony_ci int i = 0; 11548c2ecf20Sopenharmony_ci u32 max_out_io, ccb_count; 11558c2ecf20Sopenharmony_ci u32 can_queue; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci max_out_io = pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_out_io; 11588c2ecf20Sopenharmony_ci ccb_count = min_t(int, PM8001_MAX_CCB, max_out_io); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci /* Update to the scsi host*/ 11618c2ecf20Sopenharmony_ci can_queue = ccb_count - PM8001_RESERVE_SLOT; 11628c2ecf20Sopenharmony_ci shost->can_queue = can_queue; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci pm8001_ha->tags = kzalloc(ccb_count, GFP_KERNEL); 11658c2ecf20Sopenharmony_ci if (!pm8001_ha->tags) 11668c2ecf20Sopenharmony_ci goto err_out; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci /* Memory region for ccb_info*/ 11698c2ecf20Sopenharmony_ci pm8001_ha->ccb_info = (struct pm8001_ccb_info *) 11708c2ecf20Sopenharmony_ci kcalloc(ccb_count, sizeof(struct pm8001_ccb_info), GFP_KERNEL); 11718c2ecf20Sopenharmony_ci if (!pm8001_ha->ccb_info) { 11728c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 11738c2ecf20Sopenharmony_ci "Unable to allocate memory for ccb\n"); 11748c2ecf20Sopenharmony_ci goto err_out_noccb; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci for (i = 0; i < ccb_count; i++) { 11778c2ecf20Sopenharmony_ci pm8001_ha->ccb_info[i].buf_prd = pci_alloc_consistent(pdev, 11788c2ecf20Sopenharmony_ci sizeof(struct pm8001_prd) * PM8001_MAX_DMA_SG, 11798c2ecf20Sopenharmony_ci &pm8001_ha->ccb_info[i].ccb_dma_handle); 11808c2ecf20Sopenharmony_ci if (!pm8001_ha->ccb_info[i].buf_prd) { 11818c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 11828c2ecf20Sopenharmony_ci "pm80xx: ccb prd memory allocation error\n"); 11838c2ecf20Sopenharmony_ci goto err_out; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci pm8001_ha->ccb_info[i].task = NULL; 11868c2ecf20Sopenharmony_ci pm8001_ha->ccb_info[i].ccb_tag = 0xffffffff; 11878c2ecf20Sopenharmony_ci pm8001_ha->ccb_info[i].device = NULL; 11888c2ecf20Sopenharmony_ci ++pm8001_ha->tags_num; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci return 0; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cierr_out_noccb: 11938c2ecf20Sopenharmony_ci kfree(pm8001_ha->devices); 11948c2ecf20Sopenharmony_cierr_out: 11958c2ecf20Sopenharmony_ci return -ENOMEM; 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_cistatic void pm8001_pci_remove(struct pci_dev *pdev) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = pci_get_drvdata(pdev); 12018c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha; 12028c2ecf20Sopenharmony_ci int i, j; 12038c2ecf20Sopenharmony_ci pm8001_ha = sha->lldd_ha; 12048c2ecf20Sopenharmony_ci sas_unregister_ha(sha); 12058c2ecf20Sopenharmony_ci sas_remove_host(pm8001_ha->shost); 12068c2ecf20Sopenharmony_ci list_del(&pm8001_ha->list); 12078c2ecf20Sopenharmony_ci PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF); 12088c2ecf20Sopenharmony_ci PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci#ifdef PM8001_USE_MSIX 12118c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->number_of_intr; i++) 12128c2ecf20Sopenharmony_ci synchronize_irq(pci_irq_vector(pdev, i)); 12138c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->number_of_intr; i++) 12148c2ecf20Sopenharmony_ci free_irq(pci_irq_vector(pdev, i), &pm8001_ha->irq_vector[i]); 12158c2ecf20Sopenharmony_ci pci_free_irq_vectors(pdev); 12168c2ecf20Sopenharmony_ci#else 12178c2ecf20Sopenharmony_ci free_irq(pm8001_ha->irq, sha); 12188c2ecf20Sopenharmony_ci#endif 12198c2ecf20Sopenharmony_ci#ifdef PM8001_USE_TASKLET 12208c2ecf20Sopenharmony_ci /* For non-msix and msix interrupts */ 12218c2ecf20Sopenharmony_ci if ((!pdev->msix_cap || !pci_msi_enabled()) || 12228c2ecf20Sopenharmony_ci (pm8001_ha->chip_id == chip_8001)) 12238c2ecf20Sopenharmony_ci tasklet_kill(&pm8001_ha->tasklet[0]); 12248c2ecf20Sopenharmony_ci else 12258c2ecf20Sopenharmony_ci for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) 12268c2ecf20Sopenharmony_ci tasklet_kill(&pm8001_ha->tasklet[j]); 12278c2ecf20Sopenharmony_ci#endif 12288c2ecf20Sopenharmony_ci scsi_host_put(pm8001_ha->shost); 12298c2ecf20Sopenharmony_ci pm8001_free(pm8001_ha); 12308c2ecf20Sopenharmony_ci kfree(sha->sas_phy); 12318c2ecf20Sopenharmony_ci kfree(sha->sas_port); 12328c2ecf20Sopenharmony_ci kfree(sha); 12338c2ecf20Sopenharmony_ci pci_release_regions(pdev); 12348c2ecf20Sopenharmony_ci pci_disable_device(pdev); 12358c2ecf20Sopenharmony_ci} 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci/** 12388c2ecf20Sopenharmony_ci * pm8001_pci_suspend - power management suspend main entry point 12398c2ecf20Sopenharmony_ci * @pdev: PCI device struct 12408c2ecf20Sopenharmony_ci * @state: PM state change to (usually PCI_D3) 12418c2ecf20Sopenharmony_ci * 12428c2ecf20Sopenharmony_ci * Returns 0 success, anything else error. 12438c2ecf20Sopenharmony_ci */ 12448c2ecf20Sopenharmony_cistatic int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state) 12458c2ecf20Sopenharmony_ci{ 12468c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = pci_get_drvdata(pdev); 12478c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha; 12488c2ecf20Sopenharmony_ci int i, j; 12498c2ecf20Sopenharmony_ci u32 device_state; 12508c2ecf20Sopenharmony_ci pm8001_ha = sha->lldd_ha; 12518c2ecf20Sopenharmony_ci sas_suspend_ha(sha); 12528c2ecf20Sopenharmony_ci flush_workqueue(pm8001_wq); 12538c2ecf20Sopenharmony_ci scsi_block_requests(pm8001_ha->shost); 12548c2ecf20Sopenharmony_ci if (!pdev->pm_cap) { 12558c2ecf20Sopenharmony_ci dev_err(&pdev->dev, " PCI PM not supported\n"); 12568c2ecf20Sopenharmony_ci return -ENODEV; 12578c2ecf20Sopenharmony_ci } 12588c2ecf20Sopenharmony_ci PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF); 12598c2ecf20Sopenharmony_ci PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha); 12608c2ecf20Sopenharmony_ci#ifdef PM8001_USE_MSIX 12618c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->number_of_intr; i++) 12628c2ecf20Sopenharmony_ci synchronize_irq(pci_irq_vector(pdev, i)); 12638c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->number_of_intr; i++) 12648c2ecf20Sopenharmony_ci free_irq(pci_irq_vector(pdev, i), &pm8001_ha->irq_vector[i]); 12658c2ecf20Sopenharmony_ci pci_free_irq_vectors(pdev); 12668c2ecf20Sopenharmony_ci#else 12678c2ecf20Sopenharmony_ci free_irq(pm8001_ha->irq, sha); 12688c2ecf20Sopenharmony_ci#endif 12698c2ecf20Sopenharmony_ci#ifdef PM8001_USE_TASKLET 12708c2ecf20Sopenharmony_ci /* For non-msix and msix interrupts */ 12718c2ecf20Sopenharmony_ci if ((!pdev->msix_cap || !pci_msi_enabled()) || 12728c2ecf20Sopenharmony_ci (pm8001_ha->chip_id == chip_8001)) 12738c2ecf20Sopenharmony_ci tasklet_kill(&pm8001_ha->tasklet[0]); 12748c2ecf20Sopenharmony_ci else 12758c2ecf20Sopenharmony_ci for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) 12768c2ecf20Sopenharmony_ci tasklet_kill(&pm8001_ha->tasklet[j]); 12778c2ecf20Sopenharmony_ci#endif 12788c2ecf20Sopenharmony_ci device_state = pci_choose_state(pdev, state); 12798c2ecf20Sopenharmony_ci pm8001_printk("pdev=0x%p, slot=%s, entering " 12808c2ecf20Sopenharmony_ci "operating state [D%d]\n", pdev, 12818c2ecf20Sopenharmony_ci pm8001_ha->name, device_state); 12828c2ecf20Sopenharmony_ci pci_save_state(pdev); 12838c2ecf20Sopenharmony_ci pci_disable_device(pdev); 12848c2ecf20Sopenharmony_ci pci_set_power_state(pdev, device_state); 12858c2ecf20Sopenharmony_ci return 0; 12868c2ecf20Sopenharmony_ci} 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci/** 12898c2ecf20Sopenharmony_ci * pm8001_pci_resume - power management resume main entry point 12908c2ecf20Sopenharmony_ci * @pdev: PCI device struct 12918c2ecf20Sopenharmony_ci * 12928c2ecf20Sopenharmony_ci * Returns 0 success, anything else error. 12938c2ecf20Sopenharmony_ci */ 12948c2ecf20Sopenharmony_cistatic int pm8001_pci_resume(struct pci_dev *pdev) 12958c2ecf20Sopenharmony_ci{ 12968c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = pci_get_drvdata(pdev); 12978c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha; 12988c2ecf20Sopenharmony_ci int rc; 12998c2ecf20Sopenharmony_ci u8 i = 0, j; 13008c2ecf20Sopenharmony_ci u32 device_state; 13018c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(completion); 13028c2ecf20Sopenharmony_ci pm8001_ha = sha->lldd_ha; 13038c2ecf20Sopenharmony_ci device_state = pdev->current_state; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci pm8001_printk("pdev=0x%p, slot=%s, resuming from previous " 13068c2ecf20Sopenharmony_ci "operating state [D%d]\n", pdev, pm8001_ha->name, device_state); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci pci_set_power_state(pdev, PCI_D0); 13098c2ecf20Sopenharmony_ci pci_enable_wake(pdev, PCI_D0, 0); 13108c2ecf20Sopenharmony_ci pci_restore_state(pdev); 13118c2ecf20Sopenharmony_ci rc = pci_enable_device(pdev); 13128c2ecf20Sopenharmony_ci if (rc) { 13138c2ecf20Sopenharmony_ci pm8001_printk("slot=%s Enable device failed during resume\n", 13148c2ecf20Sopenharmony_ci pm8001_ha->name); 13158c2ecf20Sopenharmony_ci goto err_out_enable; 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci pci_set_master(pdev); 13198c2ecf20Sopenharmony_ci rc = pci_go_44(pdev); 13208c2ecf20Sopenharmony_ci if (rc) 13218c2ecf20Sopenharmony_ci goto err_out_disable; 13228c2ecf20Sopenharmony_ci sas_prep_resume_ha(sha); 13238c2ecf20Sopenharmony_ci /* chip soft rst only for spc */ 13248c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id == chip_8001) { 13258c2ecf20Sopenharmony_ci PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha); 13268c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "chip soft reset successful\n"); 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci rc = PM8001_CHIP_DISP->chip_init(pm8001_ha); 13298c2ecf20Sopenharmony_ci if (rc) 13308c2ecf20Sopenharmony_ci goto err_out_disable; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci /* disable all the interrupt bits */ 13338c2ecf20Sopenharmony_ci PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci rc = pm8001_request_irq(pm8001_ha); 13368c2ecf20Sopenharmony_ci if (rc) 13378c2ecf20Sopenharmony_ci goto err_out_disable; 13388c2ecf20Sopenharmony_ci#ifdef PM8001_USE_TASKLET 13398c2ecf20Sopenharmony_ci /* Tasklet for non msi-x interrupt handler */ 13408c2ecf20Sopenharmony_ci if ((!pdev->msix_cap || !pci_msi_enabled()) || 13418c2ecf20Sopenharmony_ci (pm8001_ha->chip_id == chip_8001)) 13428c2ecf20Sopenharmony_ci tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet, 13438c2ecf20Sopenharmony_ci (unsigned long)&(pm8001_ha->irq_vector[0])); 13448c2ecf20Sopenharmony_ci else 13458c2ecf20Sopenharmony_ci for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) 13468c2ecf20Sopenharmony_ci tasklet_init(&pm8001_ha->tasklet[j], pm8001_tasklet, 13478c2ecf20Sopenharmony_ci (unsigned long)&(pm8001_ha->irq_vector[j])); 13488c2ecf20Sopenharmony_ci#endif 13498c2ecf20Sopenharmony_ci PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, 0); 13508c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id != chip_8001) { 13518c2ecf20Sopenharmony_ci for (i = 1; i < pm8001_ha->number_of_intr; i++) 13528c2ecf20Sopenharmony_ci PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, i); 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci /* Chip documentation for the 8070 and 8072 SPCv */ 13568c2ecf20Sopenharmony_ci /* states that a 500ms minimum delay is required */ 13578c2ecf20Sopenharmony_ci /* before issuing commands. Otherwise, the firmware */ 13588c2ecf20Sopenharmony_ci /* will enter an unrecoverable state. */ 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id == chip_8070 || 13618c2ecf20Sopenharmony_ci pm8001_ha->chip_id == chip_8072) { 13628c2ecf20Sopenharmony_ci mdelay(500); 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci /* Spin up the PHYs */ 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci pm8001_ha->flags = PM8001F_RUN_TIME; 13688c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->chip->n_phy; i++) { 13698c2ecf20Sopenharmony_ci pm8001_ha->phy[i].enable_completion = &completion; 13708c2ecf20Sopenharmony_ci PM8001_CHIP_DISP->phy_start_req(pm8001_ha, i); 13718c2ecf20Sopenharmony_ci wait_for_completion(&completion); 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci sas_resume_ha(sha); 13748c2ecf20Sopenharmony_ci return 0; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_cierr_out_disable: 13778c2ecf20Sopenharmony_ci scsi_remove_host(pm8001_ha->shost); 13788c2ecf20Sopenharmony_ci pci_disable_device(pdev); 13798c2ecf20Sopenharmony_cierr_out_enable: 13808c2ecf20Sopenharmony_ci return rc; 13818c2ecf20Sopenharmony_ci} 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci/* update of pci device, vendor id and driver data with 13848c2ecf20Sopenharmony_ci * unique value for each of the controller 13858c2ecf20Sopenharmony_ci */ 13868c2ecf20Sopenharmony_cistatic struct pci_device_id pm8001_pci_table[] = { 13878c2ecf20Sopenharmony_ci { PCI_VDEVICE(PMC_Sierra, 0x8001), chip_8001 }, 13888c2ecf20Sopenharmony_ci { PCI_VDEVICE(PMC_Sierra, 0x8006), chip_8006 }, 13898c2ecf20Sopenharmony_ci { PCI_VDEVICE(ADAPTEC2, 0x8006), chip_8006 }, 13908c2ecf20Sopenharmony_ci { PCI_VDEVICE(ATTO, 0x0042), chip_8001 }, 13918c2ecf20Sopenharmony_ci /* Support for SPC/SPCv/SPCve controllers */ 13928c2ecf20Sopenharmony_ci { PCI_VDEVICE(ADAPTEC2, 0x8001), chip_8001 }, 13938c2ecf20Sopenharmony_ci { PCI_VDEVICE(PMC_Sierra, 0x8008), chip_8008 }, 13948c2ecf20Sopenharmony_ci { PCI_VDEVICE(ADAPTEC2, 0x8008), chip_8008 }, 13958c2ecf20Sopenharmony_ci { PCI_VDEVICE(PMC_Sierra, 0x8018), chip_8018 }, 13968c2ecf20Sopenharmony_ci { PCI_VDEVICE(ADAPTEC2, 0x8018), chip_8018 }, 13978c2ecf20Sopenharmony_ci { PCI_VDEVICE(PMC_Sierra, 0x8009), chip_8009 }, 13988c2ecf20Sopenharmony_ci { PCI_VDEVICE(ADAPTEC2, 0x8009), chip_8009 }, 13998c2ecf20Sopenharmony_ci { PCI_VDEVICE(PMC_Sierra, 0x8019), chip_8019 }, 14008c2ecf20Sopenharmony_ci { PCI_VDEVICE(ADAPTEC2, 0x8019), chip_8019 }, 14018c2ecf20Sopenharmony_ci { PCI_VDEVICE(PMC_Sierra, 0x8074), chip_8074 }, 14028c2ecf20Sopenharmony_ci { PCI_VDEVICE(ADAPTEC2, 0x8074), chip_8074 }, 14038c2ecf20Sopenharmony_ci { PCI_VDEVICE(PMC_Sierra, 0x8076), chip_8076 }, 14048c2ecf20Sopenharmony_ci { PCI_VDEVICE(ADAPTEC2, 0x8076), chip_8076 }, 14058c2ecf20Sopenharmony_ci { PCI_VDEVICE(PMC_Sierra, 0x8077), chip_8077 }, 14068c2ecf20Sopenharmony_ci { PCI_VDEVICE(ADAPTEC2, 0x8077), chip_8077 }, 14078c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8081, 14088c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x0400, 0, 0, chip_8001 }, 14098c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8081, 14108c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x0800, 0, 0, chip_8001 }, 14118c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8088, 14128c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x0008, 0, 0, chip_8008 }, 14138c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8088, 14148c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x0800, 0, 0, chip_8008 }, 14158c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8089, 14168c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x0008, 0, 0, chip_8009 }, 14178c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8089, 14188c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x0800, 0, 0, chip_8009 }, 14198c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8088, 14208c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x0016, 0, 0, chip_8018 }, 14218c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8088, 14228c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x1600, 0, 0, chip_8018 }, 14238c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8089, 14248c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x0016, 0, 0, chip_8019 }, 14258c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8089, 14268c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x1600, 0, 0, chip_8019 }, 14278c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8074, 14288c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x0800, 0, 0, chip_8074 }, 14298c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8076, 14308c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x1600, 0, 0, chip_8076 }, 14318c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8077, 14328c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x1600, 0, 0, chip_8077 }, 14338c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8074, 14348c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x0008, 0, 0, chip_8074 }, 14358c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8076, 14368c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x0016, 0, 0, chip_8076 }, 14378c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8077, 14388c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x0016, 0, 0, chip_8077 }, 14398c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8076, 14408c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x0808, 0, 0, chip_8076 }, 14418c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8077, 14428c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x0808, 0, 0, chip_8077 }, 14438c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ADAPTEC2, 0x8074, 14448c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2, 0x0404, 0, 0, chip_8074 }, 14458c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ATTO, 0x8070, 14468c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ATTO, 0x0070, 0, 0, chip_8070 }, 14478c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ATTO, 0x8070, 14488c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ATTO, 0x0071, 0, 0, chip_8070 }, 14498c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ATTO, 0x8072, 14508c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ATTO, 0x0072, 0, 0, chip_8072 }, 14518c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ATTO, 0x8072, 14528c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ATTO, 0x0073, 0, 0, chip_8072 }, 14538c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ATTO, 0x8070, 14548c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ATTO, 0x0080, 0, 0, chip_8070 }, 14558c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ATTO, 0x8072, 14568c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ATTO, 0x0081, 0, 0, chip_8072 }, 14578c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ATTO, 0x8072, 14588c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ATTO, 0x0082, 0, 0, chip_8072 }, 14598c2ecf20Sopenharmony_ci {} /* terminate list */ 14608c2ecf20Sopenharmony_ci}; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_cistatic struct pci_driver pm8001_pci_driver = { 14638c2ecf20Sopenharmony_ci .name = DRV_NAME, 14648c2ecf20Sopenharmony_ci .id_table = pm8001_pci_table, 14658c2ecf20Sopenharmony_ci .probe = pm8001_pci_probe, 14668c2ecf20Sopenharmony_ci .remove = pm8001_pci_remove, 14678c2ecf20Sopenharmony_ci .suspend = pm8001_pci_suspend, 14688c2ecf20Sopenharmony_ci .resume = pm8001_pci_resume, 14698c2ecf20Sopenharmony_ci}; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci/** 14728c2ecf20Sopenharmony_ci * pm8001_init - initialize scsi transport template 14738c2ecf20Sopenharmony_ci */ 14748c2ecf20Sopenharmony_cistatic int __init pm8001_init(void) 14758c2ecf20Sopenharmony_ci{ 14768c2ecf20Sopenharmony_ci int rc = -ENOMEM; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci pm8001_wq = alloc_workqueue("pm80xx", 0, 0); 14798c2ecf20Sopenharmony_ci if (!pm8001_wq) 14808c2ecf20Sopenharmony_ci goto err; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci pm8001_id = 0; 14838c2ecf20Sopenharmony_ci pm8001_stt = sas_domain_attach_transport(&pm8001_transport_ops); 14848c2ecf20Sopenharmony_ci if (!pm8001_stt) 14858c2ecf20Sopenharmony_ci goto err_wq; 14868c2ecf20Sopenharmony_ci rc = pci_register_driver(&pm8001_pci_driver); 14878c2ecf20Sopenharmony_ci if (rc) 14888c2ecf20Sopenharmony_ci goto err_tp; 14898c2ecf20Sopenharmony_ci return 0; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_cierr_tp: 14928c2ecf20Sopenharmony_ci sas_release_transport(pm8001_stt); 14938c2ecf20Sopenharmony_cierr_wq: 14948c2ecf20Sopenharmony_ci destroy_workqueue(pm8001_wq); 14958c2ecf20Sopenharmony_cierr: 14968c2ecf20Sopenharmony_ci return rc; 14978c2ecf20Sopenharmony_ci} 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_cistatic void __exit pm8001_exit(void) 15008c2ecf20Sopenharmony_ci{ 15018c2ecf20Sopenharmony_ci pci_unregister_driver(&pm8001_pci_driver); 15028c2ecf20Sopenharmony_ci sas_release_transport(pm8001_stt); 15038c2ecf20Sopenharmony_ci destroy_workqueue(pm8001_wq); 15048c2ecf20Sopenharmony_ci} 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_cimodule_init(pm8001_init); 15078c2ecf20Sopenharmony_cimodule_exit(pm8001_exit); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jack Wang <jack_wang@usish.com>"); 15108c2ecf20Sopenharmony_ciMODULE_AUTHOR("Anand Kumar Santhanam <AnandKumar.Santhanam@pmcs.com>"); 15118c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sangeetha Gnanasekaran <Sangeetha.Gnanasekaran@pmcs.com>"); 15128c2ecf20Sopenharmony_ciMODULE_AUTHOR("Nikith Ganigarakoppal <Nikith.Ganigarakoppal@pmcs.com>"); 15138c2ecf20Sopenharmony_ciMODULE_DESCRIPTION( 15148c2ecf20Sopenharmony_ci "PMC-Sierra PM8001/8006/8081/8088/8089/8074/8076/8077/8070/8072 " 15158c2ecf20Sopenharmony_ci "SAS/SATA controller driver"); 15168c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 15178c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 15188c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pm8001_pci_table); 15198c2ecf20Sopenharmony_ci 1520