18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Marvell 88SE64xx/88SE94xx pci init 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2007 Red Hat, Inc. 68c2ecf20Sopenharmony_ci * Copyright 2008 Marvell. <kewei@marvell.com> 78c2ecf20Sopenharmony_ci * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> 88c2ecf20Sopenharmony_ci*/ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "mv_sas.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ciint interrupt_coalescing = 0x80; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic struct scsi_transport_template *mvs_stt; 168c2ecf20Sopenharmony_cistatic const struct mvs_chip_info mvs_chips[] = { 178c2ecf20Sopenharmony_ci [chip_6320] = { 1, 2, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, }, 188c2ecf20Sopenharmony_ci [chip_6440] = { 1, 4, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, }, 198c2ecf20Sopenharmony_ci [chip_6485] = { 1, 8, 0x800, 33, 32, 6, 10, &mvs_64xx_dispatch, }, 208c2ecf20Sopenharmony_ci [chip_9180] = { 2, 4, 0x800, 17, 64, 8, 9, &mvs_94xx_dispatch, }, 218c2ecf20Sopenharmony_ci [chip_9480] = { 2, 4, 0x800, 17, 64, 8, 9, &mvs_94xx_dispatch, }, 228c2ecf20Sopenharmony_ci [chip_9445] = { 1, 4, 0x800, 17, 64, 8, 11, &mvs_94xx_dispatch, }, 238c2ecf20Sopenharmony_ci [chip_9485] = { 2, 4, 0x800, 17, 64, 8, 11, &mvs_94xx_dispatch, }, 248c2ecf20Sopenharmony_ci [chip_1300] = { 1, 4, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, }, 258c2ecf20Sopenharmony_ci [chip_1320] = { 2, 4, 0x800, 17, 64, 8, 9, &mvs_94xx_dispatch, }, 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic struct device_attribute *mvst_host_attrs[]; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define SOC_SAS_NUM 2 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic struct scsi_host_template mvs_sht = { 338c2ecf20Sopenharmony_ci .module = THIS_MODULE, 348c2ecf20Sopenharmony_ci .name = DRV_NAME, 358c2ecf20Sopenharmony_ci .queuecommand = sas_queuecommand, 368c2ecf20Sopenharmony_ci .dma_need_drain = ata_scsi_dma_need_drain, 378c2ecf20Sopenharmony_ci .target_alloc = sas_target_alloc, 388c2ecf20Sopenharmony_ci .slave_configure = sas_slave_configure, 398c2ecf20Sopenharmony_ci .scan_finished = mvs_scan_finished, 408c2ecf20Sopenharmony_ci .scan_start = mvs_scan_start, 418c2ecf20Sopenharmony_ci .change_queue_depth = sas_change_queue_depth, 428c2ecf20Sopenharmony_ci .bios_param = sas_bios_param, 438c2ecf20Sopenharmony_ci .can_queue = 1, 448c2ecf20Sopenharmony_ci .this_id = -1, 458c2ecf20Sopenharmony_ci .sg_tablesize = SG_ALL, 468c2ecf20Sopenharmony_ci .max_sectors = SCSI_DEFAULT_MAX_SECTORS, 478c2ecf20Sopenharmony_ci .eh_device_reset_handler = sas_eh_device_reset_handler, 488c2ecf20Sopenharmony_ci .eh_target_reset_handler = sas_eh_target_reset_handler, 498c2ecf20Sopenharmony_ci .slave_alloc = sas_slave_alloc, 508c2ecf20Sopenharmony_ci .target_destroy = sas_target_destroy, 518c2ecf20Sopenharmony_ci .ioctl = sas_ioctl, 528c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 538c2ecf20Sopenharmony_ci .compat_ioctl = sas_ioctl, 548c2ecf20Sopenharmony_ci#endif 558c2ecf20Sopenharmony_ci .shost_attrs = mvst_host_attrs, 568c2ecf20Sopenharmony_ci .track_queue_depth = 1, 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic struct sas_domain_function_template mvs_transport_ops = { 608c2ecf20Sopenharmony_ci .lldd_dev_found = mvs_dev_found, 618c2ecf20Sopenharmony_ci .lldd_dev_gone = mvs_dev_gone, 628c2ecf20Sopenharmony_ci .lldd_execute_task = mvs_queue_command, 638c2ecf20Sopenharmony_ci .lldd_control_phy = mvs_phy_control, 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci .lldd_abort_task = mvs_abort_task, 668c2ecf20Sopenharmony_ci .lldd_abort_task_set = mvs_abort_task_set, 678c2ecf20Sopenharmony_ci .lldd_clear_aca = mvs_clear_aca, 688c2ecf20Sopenharmony_ci .lldd_clear_task_set = mvs_clear_task_set, 698c2ecf20Sopenharmony_ci .lldd_I_T_nexus_reset = mvs_I_T_nexus_reset, 708c2ecf20Sopenharmony_ci .lldd_lu_reset = mvs_lu_reset, 718c2ecf20Sopenharmony_ci .lldd_query_task = mvs_query_task, 728c2ecf20Sopenharmony_ci .lldd_port_formed = mvs_port_formed, 738c2ecf20Sopenharmony_ci .lldd_port_deformed = mvs_port_deformed, 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci .lldd_write_gpio = mvs_gpio_write, 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic void mvs_phy_init(struct mvs_info *mvi, int phy_id) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[phy_id]; 828c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy = &phy->sas_phy; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci phy->mvi = mvi; 858c2ecf20Sopenharmony_ci phy->port = NULL; 868c2ecf20Sopenharmony_ci timer_setup(&phy->timer, NULL, 0); 878c2ecf20Sopenharmony_ci sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0; 888c2ecf20Sopenharmony_ci sas_phy->class = SAS; 898c2ecf20Sopenharmony_ci sas_phy->iproto = SAS_PROTOCOL_ALL; 908c2ecf20Sopenharmony_ci sas_phy->tproto = 0; 918c2ecf20Sopenharmony_ci sas_phy->type = PHY_TYPE_PHYSICAL; 928c2ecf20Sopenharmony_ci sas_phy->role = PHY_ROLE_INITIATOR; 938c2ecf20Sopenharmony_ci sas_phy->oob_mode = OOB_NOT_CONNECTED; 948c2ecf20Sopenharmony_ci sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci sas_phy->id = phy_id; 978c2ecf20Sopenharmony_ci sas_phy->sas_addr = &mvi->sas_addr[0]; 988c2ecf20Sopenharmony_ci sas_phy->frame_rcvd = &phy->frame_rcvd[0]; 998c2ecf20Sopenharmony_ci sas_phy->ha = (struct sas_ha_struct *)mvi->shost->hostdata; 1008c2ecf20Sopenharmony_ci sas_phy->lldd_phy = phy; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic void mvs_free(struct mvs_info *mvi) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct mvs_wq *mwq; 1068c2ecf20Sopenharmony_ci int slot_nr; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (!mvi) 1098c2ecf20Sopenharmony_ci return; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (mvi->flags & MVF_FLAG_SOC) 1128c2ecf20Sopenharmony_ci slot_nr = MVS_SOC_SLOTS; 1138c2ecf20Sopenharmony_ci else 1148c2ecf20Sopenharmony_ci slot_nr = MVS_CHIP_SLOT_SZ; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci dma_pool_destroy(mvi->dma_pool); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (mvi->tx) 1198c2ecf20Sopenharmony_ci dma_free_coherent(mvi->dev, 1208c2ecf20Sopenharmony_ci sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ, 1218c2ecf20Sopenharmony_ci mvi->tx, mvi->tx_dma); 1228c2ecf20Sopenharmony_ci if (mvi->rx_fis) 1238c2ecf20Sopenharmony_ci dma_free_coherent(mvi->dev, MVS_RX_FISL_SZ, 1248c2ecf20Sopenharmony_ci mvi->rx_fis, mvi->rx_fis_dma); 1258c2ecf20Sopenharmony_ci if (mvi->rx) 1268c2ecf20Sopenharmony_ci dma_free_coherent(mvi->dev, 1278c2ecf20Sopenharmony_ci sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1), 1288c2ecf20Sopenharmony_ci mvi->rx, mvi->rx_dma); 1298c2ecf20Sopenharmony_ci if (mvi->slot) 1308c2ecf20Sopenharmony_ci dma_free_coherent(mvi->dev, 1318c2ecf20Sopenharmony_ci sizeof(*mvi->slot) * slot_nr, 1328c2ecf20Sopenharmony_ci mvi->slot, mvi->slot_dma); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (mvi->bulk_buffer) 1358c2ecf20Sopenharmony_ci dma_free_coherent(mvi->dev, TRASH_BUCKET_SIZE, 1368c2ecf20Sopenharmony_ci mvi->bulk_buffer, mvi->bulk_buffer_dma); 1378c2ecf20Sopenharmony_ci if (mvi->bulk_buffer1) 1388c2ecf20Sopenharmony_ci dma_free_coherent(mvi->dev, TRASH_BUCKET_SIZE, 1398c2ecf20Sopenharmony_ci mvi->bulk_buffer1, mvi->bulk_buffer_dma1); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci MVS_CHIP_DISP->chip_iounmap(mvi); 1428c2ecf20Sopenharmony_ci if (mvi->shost) 1438c2ecf20Sopenharmony_ci scsi_host_put(mvi->shost); 1448c2ecf20Sopenharmony_ci list_for_each_entry(mwq, &mvi->wq_list, entry) 1458c2ecf20Sopenharmony_ci cancel_delayed_work(&mwq->work_q); 1468c2ecf20Sopenharmony_ci kfree(mvi->tags); 1478c2ecf20Sopenharmony_ci kfree(mvi); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#ifdef CONFIG_SCSI_MVSAS_TASKLET 1518c2ecf20Sopenharmony_cistatic void mvs_tasklet(unsigned long opaque) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci u32 stat; 1548c2ecf20Sopenharmony_ci u16 core_nr, i = 0; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci struct mvs_info *mvi; 1578c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = (struct sas_ha_struct *)opaque; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; 1608c2ecf20Sopenharmony_ci mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (unlikely(!mvi)) 1638c2ecf20Sopenharmony_ci BUG_ON(1); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci stat = MVS_CHIP_DISP->isr_status(mvi, mvi->pdev->irq); 1668c2ecf20Sopenharmony_ci if (!stat) 1678c2ecf20Sopenharmony_ci goto out; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci for (i = 0; i < core_nr; i++) { 1708c2ecf20Sopenharmony_ci mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; 1718c2ecf20Sopenharmony_ci MVS_CHIP_DISP->isr(mvi, mvi->pdev->irq, stat); 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ciout: 1748c2ecf20Sopenharmony_ci MVS_CHIP_DISP->interrupt_enable(mvi); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci#endif 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic irqreturn_t mvs_interrupt(int irq, void *opaque) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci u32 stat; 1828c2ecf20Sopenharmony_ci struct mvs_info *mvi; 1838c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = opaque; 1848c2ecf20Sopenharmony_ci#ifndef CONFIG_SCSI_MVSAS_TASKLET 1858c2ecf20Sopenharmony_ci u32 i; 1868c2ecf20Sopenharmony_ci u32 core_nr; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; 1898c2ecf20Sopenharmony_ci#endif 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (unlikely(!mvi)) 1948c2ecf20Sopenharmony_ci return IRQ_NONE; 1958c2ecf20Sopenharmony_ci#ifdef CONFIG_SCSI_MVSAS_TASKLET 1968c2ecf20Sopenharmony_ci MVS_CHIP_DISP->interrupt_disable(mvi); 1978c2ecf20Sopenharmony_ci#endif 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci stat = MVS_CHIP_DISP->isr_status(mvi, irq); 2008c2ecf20Sopenharmony_ci if (!stat) { 2018c2ecf20Sopenharmony_ci #ifdef CONFIG_SCSI_MVSAS_TASKLET 2028c2ecf20Sopenharmony_ci MVS_CHIP_DISP->interrupt_enable(mvi); 2038c2ecf20Sopenharmony_ci #endif 2048c2ecf20Sopenharmony_ci return IRQ_NONE; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci#ifdef CONFIG_SCSI_MVSAS_TASKLET 2088c2ecf20Sopenharmony_ci tasklet_schedule(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet); 2098c2ecf20Sopenharmony_ci#else 2108c2ecf20Sopenharmony_ci for (i = 0; i < core_nr; i++) { 2118c2ecf20Sopenharmony_ci mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; 2128c2ecf20Sopenharmony_ci MVS_CHIP_DISP->isr(mvi, irq, stat); 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci#endif 2158c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic int mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci int i = 0, slot_nr; 2218c2ecf20Sopenharmony_ci char pool_name[32]; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (mvi->flags & MVF_FLAG_SOC) 2248c2ecf20Sopenharmony_ci slot_nr = MVS_SOC_SLOTS; 2258c2ecf20Sopenharmony_ci else 2268c2ecf20Sopenharmony_ci slot_nr = MVS_CHIP_SLOT_SZ; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci spin_lock_init(&mvi->lock); 2298c2ecf20Sopenharmony_ci for (i = 0; i < mvi->chip->n_phy; i++) { 2308c2ecf20Sopenharmony_ci mvs_phy_init(mvi, i); 2318c2ecf20Sopenharmony_ci mvi->port[i].wide_port_phymap = 0; 2328c2ecf20Sopenharmony_ci mvi->port[i].port_attached = 0; 2338c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&mvi->port[i].list); 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci for (i = 0; i < MVS_MAX_DEVICES; i++) { 2368c2ecf20Sopenharmony_ci mvi->devices[i].taskfileset = MVS_ID_NOT_MAPPED; 2378c2ecf20Sopenharmony_ci mvi->devices[i].dev_type = SAS_PHY_UNUSED; 2388c2ecf20Sopenharmony_ci mvi->devices[i].device_id = i; 2398c2ecf20Sopenharmony_ci mvi->devices[i].dev_status = MVS_DEV_NORMAL; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* 2438c2ecf20Sopenharmony_ci * alloc and init our DMA areas 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci mvi->tx = dma_alloc_coherent(mvi->dev, 2468c2ecf20Sopenharmony_ci sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ, 2478c2ecf20Sopenharmony_ci &mvi->tx_dma, GFP_KERNEL); 2488c2ecf20Sopenharmony_ci if (!mvi->tx) 2498c2ecf20Sopenharmony_ci goto err_out; 2508c2ecf20Sopenharmony_ci mvi->rx_fis = dma_alloc_coherent(mvi->dev, MVS_RX_FISL_SZ, 2518c2ecf20Sopenharmony_ci &mvi->rx_fis_dma, GFP_KERNEL); 2528c2ecf20Sopenharmony_ci if (!mvi->rx_fis) 2538c2ecf20Sopenharmony_ci goto err_out; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci mvi->rx = dma_alloc_coherent(mvi->dev, 2568c2ecf20Sopenharmony_ci sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1), 2578c2ecf20Sopenharmony_ci &mvi->rx_dma, GFP_KERNEL); 2588c2ecf20Sopenharmony_ci if (!mvi->rx) 2598c2ecf20Sopenharmony_ci goto err_out; 2608c2ecf20Sopenharmony_ci mvi->rx[0] = cpu_to_le32(0xfff); 2618c2ecf20Sopenharmony_ci mvi->rx_cons = 0xfff; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci mvi->slot = dma_alloc_coherent(mvi->dev, 2648c2ecf20Sopenharmony_ci sizeof(*mvi->slot) * slot_nr, 2658c2ecf20Sopenharmony_ci &mvi->slot_dma, GFP_KERNEL); 2668c2ecf20Sopenharmony_ci if (!mvi->slot) 2678c2ecf20Sopenharmony_ci goto err_out; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci mvi->bulk_buffer = dma_alloc_coherent(mvi->dev, 2708c2ecf20Sopenharmony_ci TRASH_BUCKET_SIZE, 2718c2ecf20Sopenharmony_ci &mvi->bulk_buffer_dma, GFP_KERNEL); 2728c2ecf20Sopenharmony_ci if (!mvi->bulk_buffer) 2738c2ecf20Sopenharmony_ci goto err_out; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci mvi->bulk_buffer1 = dma_alloc_coherent(mvi->dev, 2768c2ecf20Sopenharmony_ci TRASH_BUCKET_SIZE, 2778c2ecf20Sopenharmony_ci &mvi->bulk_buffer_dma1, GFP_KERNEL); 2788c2ecf20Sopenharmony_ci if (!mvi->bulk_buffer1) 2798c2ecf20Sopenharmony_ci goto err_out; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci sprintf(pool_name, "%s%d", "mvs_dma_pool", mvi->id); 2828c2ecf20Sopenharmony_ci mvi->dma_pool = dma_pool_create(pool_name, &mvi->pdev->dev, 2838c2ecf20Sopenharmony_ci MVS_SLOT_BUF_SZ, 16, 0); 2848c2ecf20Sopenharmony_ci if (!mvi->dma_pool) { 2858c2ecf20Sopenharmony_ci printk(KERN_DEBUG "failed to create dma pool %s.\n", pool_name); 2868c2ecf20Sopenharmony_ci goto err_out; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci mvi->tags_num = slot_nr; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* Initialize tags */ 2918c2ecf20Sopenharmony_ci mvs_tag_init(mvi); 2928c2ecf20Sopenharmony_ci return 0; 2938c2ecf20Sopenharmony_cierr_out: 2948c2ecf20Sopenharmony_ci return 1; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ciint mvs_ioremap(struct mvs_info *mvi, int bar, int bar_ex) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci unsigned long res_start, res_len, res_flag_ex = 0; 3018c2ecf20Sopenharmony_ci struct pci_dev *pdev = mvi->pdev; 3028c2ecf20Sopenharmony_ci if (bar_ex != -1) { 3038c2ecf20Sopenharmony_ci /* 3048c2ecf20Sopenharmony_ci * ioremap main and peripheral registers 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_ci res_start = pci_resource_start(pdev, bar_ex); 3078c2ecf20Sopenharmony_ci res_len = pci_resource_len(pdev, bar_ex); 3088c2ecf20Sopenharmony_ci if (!res_start || !res_len) 3098c2ecf20Sopenharmony_ci goto err_out; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci res_flag_ex = pci_resource_flags(pdev, bar_ex); 3128c2ecf20Sopenharmony_ci if (res_flag_ex & IORESOURCE_MEM) 3138c2ecf20Sopenharmony_ci mvi->regs_ex = ioremap(res_start, res_len); 3148c2ecf20Sopenharmony_ci else 3158c2ecf20Sopenharmony_ci mvi->regs_ex = (void *)res_start; 3168c2ecf20Sopenharmony_ci if (!mvi->regs_ex) 3178c2ecf20Sopenharmony_ci goto err_out; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci res_start = pci_resource_start(pdev, bar); 3218c2ecf20Sopenharmony_ci res_len = pci_resource_len(pdev, bar); 3228c2ecf20Sopenharmony_ci if (!res_start || !res_len) { 3238c2ecf20Sopenharmony_ci iounmap(mvi->regs_ex); 3248c2ecf20Sopenharmony_ci mvi->regs_ex = NULL; 3258c2ecf20Sopenharmony_ci goto err_out; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci mvi->regs = ioremap(res_start, res_len); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (!mvi->regs) { 3318c2ecf20Sopenharmony_ci if (mvi->regs_ex && (res_flag_ex & IORESOURCE_MEM)) 3328c2ecf20Sopenharmony_ci iounmap(mvi->regs_ex); 3338c2ecf20Sopenharmony_ci mvi->regs_ex = NULL; 3348c2ecf20Sopenharmony_ci goto err_out; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return 0; 3388c2ecf20Sopenharmony_cierr_out: 3398c2ecf20Sopenharmony_ci return -1; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_civoid mvs_iounmap(void __iomem *regs) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci iounmap(regs); 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic struct mvs_info *mvs_pci_alloc(struct pci_dev *pdev, 3488c2ecf20Sopenharmony_ci const struct pci_device_id *ent, 3498c2ecf20Sopenharmony_ci struct Scsi_Host *shost, unsigned int id) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct mvs_info *mvi = NULL; 3528c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci mvi = kzalloc(sizeof(*mvi) + 3558c2ecf20Sopenharmony_ci (1L << mvs_chips[ent->driver_data].slot_width) * 3568c2ecf20Sopenharmony_ci sizeof(struct mvs_slot_info), GFP_KERNEL); 3578c2ecf20Sopenharmony_ci if (!mvi) 3588c2ecf20Sopenharmony_ci return NULL; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci mvi->pdev = pdev; 3618c2ecf20Sopenharmony_ci mvi->dev = &pdev->dev; 3628c2ecf20Sopenharmony_ci mvi->chip_id = ent->driver_data; 3638c2ecf20Sopenharmony_ci mvi->chip = &mvs_chips[mvi->chip_id]; 3648c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&mvi->wq_list); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci ((struct mvs_prv_info *)sha->lldd_ha)->mvi[id] = mvi; 3678c2ecf20Sopenharmony_ci ((struct mvs_prv_info *)sha->lldd_ha)->n_phy = mvi->chip->n_phy; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci mvi->id = id; 3708c2ecf20Sopenharmony_ci mvi->sas = sha; 3718c2ecf20Sopenharmony_ci mvi->shost = shost; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci mvi->tags = kzalloc(MVS_CHIP_SLOT_SZ>>3, GFP_KERNEL); 3748c2ecf20Sopenharmony_ci if (!mvi->tags) 3758c2ecf20Sopenharmony_ci goto err_out; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (MVS_CHIP_DISP->chip_ioremap(mvi)) 3788c2ecf20Sopenharmony_ci goto err_out; 3798c2ecf20Sopenharmony_ci if (!mvs_alloc(mvi, shost)) 3808c2ecf20Sopenharmony_ci return mvi; 3818c2ecf20Sopenharmony_cierr_out: 3828c2ecf20Sopenharmony_ci mvs_free(mvi); 3838c2ecf20Sopenharmony_ci return NULL; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic int pci_go_64(struct pci_dev *pdev) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci int rc; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 3918c2ecf20Sopenharmony_ci if (rc) { 3928c2ecf20Sopenharmony_ci rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 3938c2ecf20Sopenharmony_ci if (rc) { 3948c2ecf20Sopenharmony_ci dev_printk(KERN_ERR, &pdev->dev, 3958c2ecf20Sopenharmony_ci "32-bit DMA enable failed\n"); 3968c2ecf20Sopenharmony_ci return rc; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci return rc; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic int mvs_prep_sas_ha_init(struct Scsi_Host *shost, 4048c2ecf20Sopenharmony_ci const struct mvs_chip_info *chip_info) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci int phy_nr, port_nr; unsigned short core_nr; 4078c2ecf20Sopenharmony_ci struct asd_sas_phy **arr_phy; 4088c2ecf20Sopenharmony_ci struct asd_sas_port **arr_port; 4098c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci core_nr = chip_info->n_host; 4128c2ecf20Sopenharmony_ci phy_nr = core_nr * chip_info->n_phy; 4138c2ecf20Sopenharmony_ci port_nr = phy_nr; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci memset(sha, 0x00, sizeof(struct sas_ha_struct)); 4168c2ecf20Sopenharmony_ci arr_phy = kcalloc(phy_nr, sizeof(void *), GFP_KERNEL); 4178c2ecf20Sopenharmony_ci arr_port = kcalloc(port_nr, sizeof(void *), GFP_KERNEL); 4188c2ecf20Sopenharmony_ci if (!arr_phy || !arr_port) 4198c2ecf20Sopenharmony_ci goto exit_free; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci sha->sas_phy = arr_phy; 4228c2ecf20Sopenharmony_ci sha->sas_port = arr_port; 4238c2ecf20Sopenharmony_ci sha->core.shost = shost; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci sha->lldd_ha = kzalloc(sizeof(struct mvs_prv_info), GFP_KERNEL); 4268c2ecf20Sopenharmony_ci if (!sha->lldd_ha) 4278c2ecf20Sopenharmony_ci goto exit_free; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci ((struct mvs_prv_info *)sha->lldd_ha)->n_host = core_nr; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci shost->transportt = mvs_stt; 4328c2ecf20Sopenharmony_ci shost->max_id = MVS_MAX_DEVICES; 4338c2ecf20Sopenharmony_ci shost->max_lun = ~0; 4348c2ecf20Sopenharmony_ci shost->max_channel = 1; 4358c2ecf20Sopenharmony_ci shost->max_cmd_len = 16; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return 0; 4388c2ecf20Sopenharmony_ciexit_free: 4398c2ecf20Sopenharmony_ci kfree(arr_phy); 4408c2ecf20Sopenharmony_ci kfree(arr_port); 4418c2ecf20Sopenharmony_ci return -1; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic void mvs_post_sas_ha_init(struct Scsi_Host *shost, 4468c2ecf20Sopenharmony_ci const struct mvs_chip_info *chip_info) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci int can_queue, i = 0, j = 0; 4498c2ecf20Sopenharmony_ci struct mvs_info *mvi = NULL; 4508c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 4518c2ecf20Sopenharmony_ci unsigned short nr_core = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci for (j = 0; j < nr_core; j++) { 4548c2ecf20Sopenharmony_ci mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[j]; 4558c2ecf20Sopenharmony_ci for (i = 0; i < chip_info->n_phy; i++) { 4568c2ecf20Sopenharmony_ci sha->sas_phy[j * chip_info->n_phy + i] = 4578c2ecf20Sopenharmony_ci &mvi->phy[i].sas_phy; 4588c2ecf20Sopenharmony_ci sha->sas_port[j * chip_info->n_phy + i] = 4598c2ecf20Sopenharmony_ci &mvi->port[i].sas_port; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci sha->sas_ha_name = DRV_NAME; 4648c2ecf20Sopenharmony_ci sha->dev = mvi->dev; 4658c2ecf20Sopenharmony_ci sha->lldd_module = THIS_MODULE; 4668c2ecf20Sopenharmony_ci sha->sas_addr = &mvi->sas_addr[0]; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci sha->num_phys = nr_core * chip_info->n_phy; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (mvi->flags & MVF_FLAG_SOC) 4718c2ecf20Sopenharmony_ci can_queue = MVS_SOC_CAN_QUEUE; 4728c2ecf20Sopenharmony_ci else 4738c2ecf20Sopenharmony_ci can_queue = MVS_CHIP_SLOT_SZ; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci shost->sg_tablesize = min_t(u16, SG_ALL, MVS_MAX_SG); 4768c2ecf20Sopenharmony_ci shost->can_queue = can_queue; 4778c2ecf20Sopenharmony_ci mvi->shost->cmd_per_lun = MVS_QUEUE_SIZE; 4788c2ecf20Sopenharmony_ci sha->core.shost = mvi->shost; 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic void mvs_init_sas_add(struct mvs_info *mvi) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci u8 i; 4848c2ecf20Sopenharmony_ci for (i = 0; i < mvi->chip->n_phy; i++) { 4858c2ecf20Sopenharmony_ci mvi->phy[i].dev_sas_addr = 0x5005043011ab0000ULL; 4868c2ecf20Sopenharmony_ci mvi->phy[i].dev_sas_addr = 4878c2ecf20Sopenharmony_ci cpu_to_be64((u64)(*(u64 *)&mvi->phy[i].dev_sas_addr)); 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci memcpy(mvi->sas_addr, &mvi->phy[0].dev_sas_addr, SAS_ADDR_SIZE); 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic int mvs_pci_init(struct pci_dev *pdev, const struct pci_device_id *ent) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci unsigned int rc, nhost = 0; 4968c2ecf20Sopenharmony_ci struct mvs_info *mvi; 4978c2ecf20Sopenharmony_ci struct mvs_prv_info *mpi; 4988c2ecf20Sopenharmony_ci irq_handler_t irq_handler = mvs_interrupt; 4998c2ecf20Sopenharmony_ci struct Scsi_Host *shost = NULL; 5008c2ecf20Sopenharmony_ci const struct mvs_chip_info *chip; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci dev_printk(KERN_INFO, &pdev->dev, 5038c2ecf20Sopenharmony_ci "mvsas: driver version %s\n", DRV_VERSION); 5048c2ecf20Sopenharmony_ci rc = pci_enable_device(pdev); 5058c2ecf20Sopenharmony_ci if (rc) 5068c2ecf20Sopenharmony_ci goto err_out_enable; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci pci_set_master(pdev); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci rc = pci_request_regions(pdev, DRV_NAME); 5118c2ecf20Sopenharmony_ci if (rc) 5128c2ecf20Sopenharmony_ci goto err_out_disable; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci rc = pci_go_64(pdev); 5158c2ecf20Sopenharmony_ci if (rc) 5168c2ecf20Sopenharmony_ci goto err_out_regions; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci shost = scsi_host_alloc(&mvs_sht, sizeof(void *)); 5198c2ecf20Sopenharmony_ci if (!shost) { 5208c2ecf20Sopenharmony_ci rc = -ENOMEM; 5218c2ecf20Sopenharmony_ci goto err_out_regions; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci chip = &mvs_chips[ent->driver_data]; 5258c2ecf20Sopenharmony_ci SHOST_TO_SAS_HA(shost) = 5268c2ecf20Sopenharmony_ci kcalloc(1, sizeof(struct sas_ha_struct), GFP_KERNEL); 5278c2ecf20Sopenharmony_ci if (!SHOST_TO_SAS_HA(shost)) { 5288c2ecf20Sopenharmony_ci scsi_host_put(shost); 5298c2ecf20Sopenharmony_ci rc = -ENOMEM; 5308c2ecf20Sopenharmony_ci goto err_out_regions; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci rc = mvs_prep_sas_ha_init(shost, chip); 5348c2ecf20Sopenharmony_ci if (rc) { 5358c2ecf20Sopenharmony_ci scsi_host_put(shost); 5368c2ecf20Sopenharmony_ci rc = -ENOMEM; 5378c2ecf20Sopenharmony_ci goto err_out_regions; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, SHOST_TO_SAS_HA(shost)); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci do { 5438c2ecf20Sopenharmony_ci mvi = mvs_pci_alloc(pdev, ent, shost, nhost); 5448c2ecf20Sopenharmony_ci if (!mvi) { 5458c2ecf20Sopenharmony_ci rc = -ENOMEM; 5468c2ecf20Sopenharmony_ci goto err_out_regions; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci memset(&mvi->hba_info_param, 0xFF, 5508c2ecf20Sopenharmony_ci sizeof(struct hba_info_page)); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci mvs_init_sas_add(mvi); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci mvi->instance = nhost; 5558c2ecf20Sopenharmony_ci rc = MVS_CHIP_DISP->chip_init(mvi); 5568c2ecf20Sopenharmony_ci if (rc) { 5578c2ecf20Sopenharmony_ci mvs_free(mvi); 5588c2ecf20Sopenharmony_ci goto err_out_regions; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci nhost++; 5618c2ecf20Sopenharmony_ci } while (nhost < chip->n_host); 5628c2ecf20Sopenharmony_ci mpi = (struct mvs_prv_info *)(SHOST_TO_SAS_HA(shost)->lldd_ha); 5638c2ecf20Sopenharmony_ci#ifdef CONFIG_SCSI_MVSAS_TASKLET 5648c2ecf20Sopenharmony_ci tasklet_init(&(mpi->mv_tasklet), mvs_tasklet, 5658c2ecf20Sopenharmony_ci (unsigned long)SHOST_TO_SAS_HA(shost)); 5668c2ecf20Sopenharmony_ci#endif 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci mvs_post_sas_ha_init(shost, chip); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci rc = scsi_add_host(shost, &pdev->dev); 5718c2ecf20Sopenharmony_ci if (rc) 5728c2ecf20Sopenharmony_ci goto err_out_shost; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci rc = sas_register_ha(SHOST_TO_SAS_HA(shost)); 5758c2ecf20Sopenharmony_ci if (rc) 5768c2ecf20Sopenharmony_ci goto err_out_shost; 5778c2ecf20Sopenharmony_ci rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, 5788c2ecf20Sopenharmony_ci DRV_NAME, SHOST_TO_SAS_HA(shost)); 5798c2ecf20Sopenharmony_ci if (rc) 5808c2ecf20Sopenharmony_ci goto err_not_sas; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci MVS_CHIP_DISP->interrupt_enable(mvi); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci scsi_scan_host(mvi->shost); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci return 0; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cierr_not_sas: 5898c2ecf20Sopenharmony_ci sas_unregister_ha(SHOST_TO_SAS_HA(shost)); 5908c2ecf20Sopenharmony_cierr_out_shost: 5918c2ecf20Sopenharmony_ci scsi_remove_host(mvi->shost); 5928c2ecf20Sopenharmony_cierr_out_regions: 5938c2ecf20Sopenharmony_ci pci_release_regions(pdev); 5948c2ecf20Sopenharmony_cierr_out_disable: 5958c2ecf20Sopenharmony_ci pci_disable_device(pdev); 5968c2ecf20Sopenharmony_cierr_out_enable: 5978c2ecf20Sopenharmony_ci return rc; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic void mvs_pci_remove(struct pci_dev *pdev) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci unsigned short core_nr, i = 0; 6038c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = pci_get_drvdata(pdev); 6048c2ecf20Sopenharmony_ci struct mvs_info *mvi = NULL; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; 6078c2ecf20Sopenharmony_ci mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci#ifdef CONFIG_SCSI_MVSAS_TASKLET 6108c2ecf20Sopenharmony_ci tasklet_kill(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet); 6118c2ecf20Sopenharmony_ci#endif 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci sas_unregister_ha(sha); 6148c2ecf20Sopenharmony_ci sas_remove_host(mvi->shost); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci MVS_CHIP_DISP->interrupt_disable(mvi); 6178c2ecf20Sopenharmony_ci free_irq(mvi->pdev->irq, sha); 6188c2ecf20Sopenharmony_ci for (i = 0; i < core_nr; i++) { 6198c2ecf20Sopenharmony_ci mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; 6208c2ecf20Sopenharmony_ci mvs_free(mvi); 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci kfree(sha->sas_phy); 6238c2ecf20Sopenharmony_ci kfree(sha->sas_port); 6248c2ecf20Sopenharmony_ci kfree(sha); 6258c2ecf20Sopenharmony_ci pci_release_regions(pdev); 6268c2ecf20Sopenharmony_ci pci_disable_device(pdev); 6278c2ecf20Sopenharmony_ci return; 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic struct pci_device_id mvs_pci_table[] = { 6318c2ecf20Sopenharmony_ci { PCI_VDEVICE(MARVELL, 0x6320), chip_6320 }, 6328c2ecf20Sopenharmony_ci { PCI_VDEVICE(MARVELL, 0x6340), chip_6440 }, 6338c2ecf20Sopenharmony_ci { 6348c2ecf20Sopenharmony_ci .vendor = PCI_VENDOR_ID_MARVELL, 6358c2ecf20Sopenharmony_ci .device = 0x6440, 6368c2ecf20Sopenharmony_ci .subvendor = PCI_ANY_ID, 6378c2ecf20Sopenharmony_ci .subdevice = 0x6480, 6388c2ecf20Sopenharmony_ci .class = 0, 6398c2ecf20Sopenharmony_ci .class_mask = 0, 6408c2ecf20Sopenharmony_ci .driver_data = chip_6485, 6418c2ecf20Sopenharmony_ci }, 6428c2ecf20Sopenharmony_ci { PCI_VDEVICE(MARVELL, 0x6440), chip_6440 }, 6438c2ecf20Sopenharmony_ci { PCI_VDEVICE(MARVELL, 0x6485), chip_6485 }, 6448c2ecf20Sopenharmony_ci { PCI_VDEVICE(MARVELL, 0x9480), chip_9480 }, 6458c2ecf20Sopenharmony_ci { PCI_VDEVICE(MARVELL, 0x9180), chip_9180 }, 6468c2ecf20Sopenharmony_ci { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1300), chip_1300 }, 6478c2ecf20Sopenharmony_ci { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1320), chip_1320 }, 6488c2ecf20Sopenharmony_ci { PCI_VDEVICE(ADAPTEC2, 0x0450), chip_6440 }, 6498c2ecf20Sopenharmony_ci { PCI_VDEVICE(TTI, 0x2640), chip_6440 }, 6508c2ecf20Sopenharmony_ci { PCI_VDEVICE(TTI, 0x2710), chip_9480 }, 6518c2ecf20Sopenharmony_ci { PCI_VDEVICE(TTI, 0x2720), chip_9480 }, 6528c2ecf20Sopenharmony_ci { PCI_VDEVICE(TTI, 0x2721), chip_9480 }, 6538c2ecf20Sopenharmony_ci { PCI_VDEVICE(TTI, 0x2722), chip_9480 }, 6548c2ecf20Sopenharmony_ci { PCI_VDEVICE(TTI, 0x2740), chip_9480 }, 6558c2ecf20Sopenharmony_ci { PCI_VDEVICE(TTI, 0x2744), chip_9480 }, 6568c2ecf20Sopenharmony_ci { PCI_VDEVICE(TTI, 0x2760), chip_9480 }, 6578c2ecf20Sopenharmony_ci { 6588c2ecf20Sopenharmony_ci .vendor = PCI_VENDOR_ID_MARVELL_EXT, 6598c2ecf20Sopenharmony_ci .device = 0x9480, 6608c2ecf20Sopenharmony_ci .subvendor = PCI_ANY_ID, 6618c2ecf20Sopenharmony_ci .subdevice = 0x9480, 6628c2ecf20Sopenharmony_ci .class = 0, 6638c2ecf20Sopenharmony_ci .class_mask = 0, 6648c2ecf20Sopenharmony_ci .driver_data = chip_9480, 6658c2ecf20Sopenharmony_ci }, 6668c2ecf20Sopenharmony_ci { 6678c2ecf20Sopenharmony_ci .vendor = PCI_VENDOR_ID_MARVELL_EXT, 6688c2ecf20Sopenharmony_ci .device = 0x9445, 6698c2ecf20Sopenharmony_ci .subvendor = PCI_ANY_ID, 6708c2ecf20Sopenharmony_ci .subdevice = 0x9480, 6718c2ecf20Sopenharmony_ci .class = 0, 6728c2ecf20Sopenharmony_ci .class_mask = 0, 6738c2ecf20Sopenharmony_ci .driver_data = chip_9445, 6748c2ecf20Sopenharmony_ci }, 6758c2ecf20Sopenharmony_ci { PCI_VDEVICE(MARVELL_EXT, 0x9485), chip_9485 }, /* Marvell 9480/9485 (any vendor/model) */ 6768c2ecf20Sopenharmony_ci { PCI_VDEVICE(OCZ, 0x1021), chip_9485}, /* OCZ RevoDrive3 */ 6778c2ecf20Sopenharmony_ci { PCI_VDEVICE(OCZ, 0x1022), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ 6788c2ecf20Sopenharmony_ci { PCI_VDEVICE(OCZ, 0x1040), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ 6798c2ecf20Sopenharmony_ci { PCI_VDEVICE(OCZ, 0x1041), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ 6808c2ecf20Sopenharmony_ci { PCI_VDEVICE(OCZ, 0x1042), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ 6818c2ecf20Sopenharmony_ci { PCI_VDEVICE(OCZ, 0x1043), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ 6828c2ecf20Sopenharmony_ci { PCI_VDEVICE(OCZ, 0x1044), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ 6838c2ecf20Sopenharmony_ci { PCI_VDEVICE(OCZ, 0x1080), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ 6848c2ecf20Sopenharmony_ci { PCI_VDEVICE(OCZ, 0x1083), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ 6858c2ecf20Sopenharmony_ci { PCI_VDEVICE(OCZ, 0x1084), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci { } /* terminate list */ 6888c2ecf20Sopenharmony_ci}; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cistatic struct pci_driver mvs_pci_driver = { 6918c2ecf20Sopenharmony_ci .name = DRV_NAME, 6928c2ecf20Sopenharmony_ci .id_table = mvs_pci_table, 6938c2ecf20Sopenharmony_ci .probe = mvs_pci_init, 6948c2ecf20Sopenharmony_ci .remove = mvs_pci_remove, 6958c2ecf20Sopenharmony_ci}; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_cistatic ssize_t 6988c2ecf20Sopenharmony_cimvs_show_driver_version(struct device *cdev, 6998c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buffer) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci return sysfs_emit(buffer, "%s\n", DRV_VERSION); 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic DEVICE_ATTR(driver_version, 7058c2ecf20Sopenharmony_ci S_IRUGO, 7068c2ecf20Sopenharmony_ci mvs_show_driver_version, 7078c2ecf20Sopenharmony_ci NULL); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cistatic ssize_t 7108c2ecf20Sopenharmony_cimvs_store_interrupt_coalescing(struct device *cdev, 7118c2ecf20Sopenharmony_ci struct device_attribute *attr, 7128c2ecf20Sopenharmony_ci const char *buffer, size_t size) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci unsigned int val = 0; 7158c2ecf20Sopenharmony_ci struct mvs_info *mvi = NULL; 7168c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 7178c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 7188c2ecf20Sopenharmony_ci u8 i, core_nr; 7198c2ecf20Sopenharmony_ci if (buffer == NULL) 7208c2ecf20Sopenharmony_ci return size; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci if (sscanf(buffer, "%u", &val) != 1) 7238c2ecf20Sopenharmony_ci return -EINVAL; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci if (val >= 0x10000) { 7268c2ecf20Sopenharmony_ci mv_dprintk("interrupt coalescing timer %d us is" 7278c2ecf20Sopenharmony_ci "too long\n", val); 7288c2ecf20Sopenharmony_ci return strlen(buffer); 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci interrupt_coalescing = val; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; 7348c2ecf20Sopenharmony_ci mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (unlikely(!mvi)) 7378c2ecf20Sopenharmony_ci return -EINVAL; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci for (i = 0; i < core_nr; i++) { 7408c2ecf20Sopenharmony_ci mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; 7418c2ecf20Sopenharmony_ci if (MVS_CHIP_DISP->tune_interrupt) 7428c2ecf20Sopenharmony_ci MVS_CHIP_DISP->tune_interrupt(mvi, 7438c2ecf20Sopenharmony_ci interrupt_coalescing); 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci mv_dprintk("set interrupt coalescing time to %d us\n", 7468c2ecf20Sopenharmony_ci interrupt_coalescing); 7478c2ecf20Sopenharmony_ci return strlen(buffer); 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic ssize_t mvs_show_interrupt_coalescing(struct device *cdev, 7518c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buffer) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci return sysfs_emit(buffer, "%d\n", interrupt_coalescing); 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic DEVICE_ATTR(interrupt_coalescing, 7578c2ecf20Sopenharmony_ci S_IRUGO|S_IWUSR, 7588c2ecf20Sopenharmony_ci mvs_show_interrupt_coalescing, 7598c2ecf20Sopenharmony_ci mvs_store_interrupt_coalescing); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_cistatic int __init mvs_init(void) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci int rc; 7648c2ecf20Sopenharmony_ci mvs_stt = sas_domain_attach_transport(&mvs_transport_ops); 7658c2ecf20Sopenharmony_ci if (!mvs_stt) 7668c2ecf20Sopenharmony_ci return -ENOMEM; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci rc = pci_register_driver(&mvs_pci_driver); 7698c2ecf20Sopenharmony_ci if (rc) 7708c2ecf20Sopenharmony_ci goto err_out; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci return 0; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cierr_out: 7758c2ecf20Sopenharmony_ci sas_release_transport(mvs_stt); 7768c2ecf20Sopenharmony_ci return rc; 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_cistatic void __exit mvs_exit(void) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci pci_unregister_driver(&mvs_pci_driver); 7828c2ecf20Sopenharmony_ci sas_release_transport(mvs_stt); 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic struct device_attribute *mvst_host_attrs[] = { 7868c2ecf20Sopenharmony_ci &dev_attr_driver_version, 7878c2ecf20Sopenharmony_ci &dev_attr_interrupt_coalescing, 7888c2ecf20Sopenharmony_ci NULL, 7898c2ecf20Sopenharmony_ci}; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cimodule_init(mvs_init); 7928c2ecf20Sopenharmony_cimodule_exit(mvs_exit); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>"); 7958c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver"); 7968c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 7978c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 7988c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 7998c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mvs_pci_table); 8008c2ecf20Sopenharmony_ci#endif 801