mv_sas.c revision dd4969a892ea522ecf9d7d826ba1531ce044d46f
1b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* 2dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mv_sas.c - Marvell 88SE6440 SAS/SATA support 3b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 4b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik Copyright 2007 Red Hat, Inc. 58f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei Copyright 2008 Marvell. <kewei@marvell.com> 6b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 7b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik This program is free software; you can redistribute it and/or 8b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik modify it under the terms of the GNU General Public License as 9b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik published by the Free Software Foundation; either version 2, 10b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik or (at your option) any later version. 11b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 12b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik This program is distributed in the hope that it will be useful, 13b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik but WITHOUT ANY WARRANTY; without even the implied warranty 14b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik See the GNU General Public License for more details. 16b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 17b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik You should have received a copy of the GNU General Public 18b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik License along with this program; see the file COPYING. If not, 19b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik write to the Free Software Foundation, 675 Mass Ave, Cambridge, 20b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MA 02139, USA. 21b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 22b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik --------------------------------------------------------------- 23b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 24b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik Random notes: 25b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * hardware supports controlling the endian-ness of data 26b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik structures. this permits elimination of all the le32_to_cpu() 27b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik and cpu_to_le32() conversions. 28b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 29b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 30b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 31dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#include "mv_sas.h" 32dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#include "mv_64xx.h" 33dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#include "mv_chips.h" 348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei/* offset for D2H FIS in the Received FIS List Structure */ 368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define SATA_RECEIVED_D2H_FIS(reg_set) \ 378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei ((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40) 388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define SATA_RECEIVED_PIO_FIS(reg_set) \ 398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei ((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x20) 408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define UNASSOC_D2H_FIS(id) \ 418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei ((void *) mvi->rx_fis + 0x100 * id) 428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 43dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstruct mvs_task_exec_info { 44dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct sas_task *task; 45dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_cmd_hdr *hdr; 46dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_port *port; 47dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 tag; 48dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int n_elem; 49b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 50b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 51dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_release_task(struct mvs_info *mvi, int phy_no); 52dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_is_phy_ready(struct mvs_info *mvi, int i); 53dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_update_phyinfo(struct mvs_info *mvi, int i, 54dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int get_st); 55dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_int_rx(struct mvs_info *mvi, bool self_clear); 56dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_slot_reset(struct mvs_info *mvi, struct sas_task *task, 57dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 slot_idx); 58b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 59dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag) 60dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 61dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (task->lldd_task) { 62dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_slot_info *slot; 63dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot = (struct mvs_slot_info *) task->lldd_task; 64dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik *tag = slot - mvi->slot_info; 65dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 1; 66dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 67dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 68dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 70dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_tag_clear(struct mvs_info *mvi, u32 tag) 71dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 72dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik void *bitmap = (void *) &mvi->tags; 73dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik clear_bit(tag, bitmap); 74dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 76dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_tag_free(struct mvs_info *mvi, u32 tag) 77dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 78dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_tag_clear(mvi, tag); 79dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 81dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_tag_set(struct mvs_info *mvi, unsigned int tag) 82dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 83dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik void *bitmap = (void *) &mvi->tags; 84dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik set_bit(tag, bitmap); 85dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 87dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out) 88dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 89dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik unsigned int index, tag; 90dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik void *bitmap = (void *) &mvi->tags; 91b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 92dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik index = find_first_zero_bit(bitmap, MVS_SLOTS); 93dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tag = index; 94dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (tag >= MVS_SLOTS) 95dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return -SAS_QUEUE_FULL; 96dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_tag_set(mvi, tag); 97dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik *tag_out = tag; 98dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 99dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 100b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 101dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikvoid mvs_tag_init(struct mvs_info *mvi) 102dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 103dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int i; 104dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik for (i = 0; i < MVS_SLOTS; ++i) 105dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_tag_clear(mvi, i); 106dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 107b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hexdump(u32 size, u8 *data, u32 baseaddr) 1098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 1108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u32 i; 1118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u32 run; 1128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u32 offset; 1138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei offset = 0; 1158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei while (size) { 1168f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei printk("%08X : ", baseaddr + offset); 1178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei if (size >= 16) 1188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei run = 16; 1198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei else 1208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei run = size; 1218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei size -= run; 1228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei for (i = 0; i < 16; i++) { 1238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei if (i < run) 1248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei printk("%02X ", (u32)data[i]); 1258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei else 1268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei printk(" "); 1278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei } 1288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei printk(": "); 1298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei for (i = 0; i < run; i++) 1308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei printk("%c", isalnum(data[i]) ? data[i] : '.'); 1318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei printk("\n"); 1328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei data = &data[16]; 1338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei offset += run; 1348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei } 1358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei printk("\n"); 1368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 1378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 138ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei#if _MV_DUMP 1398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag, 1408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei enum sas_protocol proto) 1418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 1428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u32 offset; 1438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei struct pci_dev *pdev = mvi->pdev; 1448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei struct mvs_slot_info *slot = &mvi->slot_info[tag]; 1458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei offset = slot->cmd_size + MVS_OAF_SZ + 1478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei sizeof(struct mvs_prd) * slot->n_elem; 1488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei dev_printk(KERN_DEBUG, &pdev->dev, "+---->Status buffer[%d] :\n", 1498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei tag); 1508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_hexdump(32, (u8 *) slot->response, 1518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei (u32) slot->buf_dma + offset); 1528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 153ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei#endif 1548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hba_memory_dump(struct mvs_info *mvi, u32 tag, 1568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei enum sas_protocol proto) 1578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 1588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP 159ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei u32 sz, w_ptr; 1608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u64 addr; 1618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei void __iomem *regs = mvi->regs; 1628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei struct pci_dev *pdev = mvi->pdev; 1638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei struct mvs_slot_info *slot = &mvi->slot_info[tag]; 1648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /*Delivery Queue */ 1668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei sz = mr32(TX_CFG) & TX_RING_SZ_MASK; 167ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei w_ptr = slot->tx; 1688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei addr = mr32(TX_HI) << 16 << 16 | mr32(TX_LO); 1698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei dev_printk(KERN_DEBUG, &pdev->dev, 170ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei "Delivery Queue Size=%04d , WRT_PTR=%04X\n", sz, w_ptr); 1718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei dev_printk(KERN_DEBUG, &pdev->dev, 1728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei "Delivery Queue Base Address=0x%llX (PA)" 1738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei "(tx_dma=0x%llX), Entry=%04d\n", 1748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei addr, mvi->tx_dma, w_ptr); 1758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_hexdump(sizeof(u32), (u8 *)(&mvi->tx[mvi->tx_prod]), 1768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei (u32) mvi->tx_dma + sizeof(u32) * w_ptr); 1778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /*Command List */ 178ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei addr = mvi->slot_dma; 1798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei dev_printk(KERN_DEBUG, &pdev->dev, 1808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei "Command List Base Address=0x%llX (PA)" 1818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei "(slot_dma=0x%llX), Header=%03d\n", 182ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei addr, slot->buf_dma, tag); 1838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei dev_printk(KERN_DEBUG, &pdev->dev, "Command Header[%03d]:\n", tag); 1848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /*mvs_cmd_hdr */ 1858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_hexdump(sizeof(struct mvs_cmd_hdr), (u8 *)(&mvi->slot[tag]), 1868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei (u32) mvi->slot_dma + tag * sizeof(struct mvs_cmd_hdr)); 1878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /*1.command table area */ 1888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei dev_printk(KERN_DEBUG, &pdev->dev, "+---->Command Table :\n"); 1898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_hexdump(slot->cmd_size, (u8 *) slot->buf, (u32) slot->buf_dma); 1908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /*2.open address frame area */ 1918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei dev_printk(KERN_DEBUG, &pdev->dev, "+---->Open Address Frame :\n"); 1928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_hexdump(MVS_OAF_SZ, (u8 *) slot->buf + slot->cmd_size, 1938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei (u32) slot->buf_dma + slot->cmd_size); 1948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /*3.status buffer */ 1958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_hba_sb_dump(mvi, tag, proto); 1968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /*4.PRD table */ 1978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei dev_printk(KERN_DEBUG, &pdev->dev, "+---->PRD table :\n"); 1988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_hexdump(sizeof(struct mvs_prd) * slot->n_elem, 1998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei (u8 *) slot->buf + slot->cmd_size + MVS_OAF_SZ, 2008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei (u32) slot->buf_dma + slot->cmd_size + MVS_OAF_SZ); 2018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif 2028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 2038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 2048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hba_cq_dump(struct mvs_info *mvi) 2058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 206ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei#if (_MV_DUMP > 2) 2078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u64 addr; 2088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei void __iomem *regs = mvi->regs; 2098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei struct pci_dev *pdev = mvi->pdev; 2108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u32 entry = mvi->rx_cons + 1; 2118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u32 rx_desc = le32_to_cpu(mvi->rx[entry]); 2128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 2138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /*Completion Queue */ 2148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei addr = mr32(RX_HI) << 16 << 16 | mr32(RX_LO); 215ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei dev_printk(KERN_DEBUG, &pdev->dev, "Completion Task = 0x%p\n", 216ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei mvi->slot_info[rx_desc & RXQ_SLOT_MASK].task); 2178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei dev_printk(KERN_DEBUG, &pdev->dev, 2188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei "Completion List Base Address=0x%llX (PA), " 2198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei "CQ_Entry=%04d, CQ_WP=0x%08X\n", 2208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei addr, entry - 1, mvi->rx[0]); 2218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_hexdump(sizeof(u32), (u8 *)(&rx_desc), 2228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvi->rx_dma + sizeof(u32) * entry); 2238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif 2248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 2258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 226dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik/* FIXME: locking? */ 227dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, void *funcdata) 2288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 229dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_info *mvi = sas_phy->ha->lldd_ha; 230dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int rc = 0, phy_id = sas_phy->id; 2318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u32 tmp; 2328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 233dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp = mvs_read_phy_ctl(mvi, phy_id); 2348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 235dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik switch (func) { 236dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case PHY_FUNC_SET_LINK_RATE:{ 237dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct sas_phy_linkrates *rates = funcdata; 238dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 lrmin = 0, lrmax = 0; 2398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 240dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik lrmin = (rates->minimum_linkrate << 8); 241dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik lrmax = (rates->maximum_linkrate << 12); 2428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 243dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (lrmin) { 244dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp &= ~(0xf << 8); 245dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp |= lrmin; 246dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 247dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (lrmax) { 248dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp &= ~(0xf << 12); 249dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp |= lrmax; 250dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 251dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_phy_ctl(mvi, phy_id, tmp); 252dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 253dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 2548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 255dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case PHY_FUNC_HARD_RESET: 256dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (tmp & PHY_RST_HARD) 257dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 258dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST_HARD); 259dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 260b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 261dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case PHY_FUNC_LINK_RESET: 262dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST); 263dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 264b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 265dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case PHY_FUNC_DISABLE: 266dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case PHY_FUNC_RELEASE_SPINUP_HOLD: 267dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik default: 268dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = -EOPNOTSUPP; 269b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 270b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 271b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 272b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 273b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 274dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_bytes_dmaed(struct mvs_info *mvi, int i) 275ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei{ 276dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_phy *phy = &mvi->phy[i]; 277dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i]; 278dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 279dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!phy->phy_attached) 280dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return; 281dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 282dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (sas_phy->phy) { 283dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct sas_phy *sphy = sas_phy->phy; 284dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 285dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sphy->negotiated_linkrate = sas_phy->linkrate; 286dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sphy->minimum_linkrate = phy->minimum_linkrate; 287dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; 288dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sphy->maximum_linkrate = phy->maximum_linkrate; 289dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sphy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; 290ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei } 291ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei 292dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy->phy_type & PORT_TYPE_SAS) { 293dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct sas_identify_frame *id; 294b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 295dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik id = (struct sas_identify_frame *)phy->frame_rcvd; 296dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik id->dev_type = phy->identify.device_type; 297dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik id->initiator_bits = SAS_PROTOCOL_ALL; 298dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik id->target_bits = phy->identify.target_port_protocols; 299dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else if (phy->phy_type & PORT_TYPE_SATA) { 300dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* TODO */ 301dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 302dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvi->sas.sas_phy[i]->frame_rcvd_size = phy->frame_rcvd_size; 303dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvi->sas.notify_port_event(mvi->sas.sas_phy[i], 304dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik PORTE_BYTES_DMAED); 305ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei} 306ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei 307dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_slave_configure(struct scsi_device *sdev) 308ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei{ 309dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct domain_device *dev = sdev_to_domain_dev(sdev); 310dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int ret = sas_slave_configure(sdev); 311b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 312dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (ret) 313dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return ret; 314ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei 315dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (dev_is_sata(dev)) { 316dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* struct ata_port *ap = dev->sata_dev.ap; */ 317dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* struct ata_device *adev = ap->link.device; */ 318dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 319dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* clamp at no NCQ for the time being */ 320dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* adev->flags |= ATA_DFLAG_NCQ_OFF; */ 321dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, 1); 322dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 323ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei return 0; 324b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 325b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 326dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikvoid mvs_scan_start(struct Scsi_Host *shost) 327b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 3288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei int i; 329dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_info *mvi = SHOST_TO_SAS_HA(shost)->lldd_ha; 330dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 331dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik for (i = 0; i < mvi->chip->n_phy; ++i) { 332dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_bytes_dmaed(mvi, i); 333dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 334b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 335b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 336dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_scan_finished(struct Scsi_Host *shost, unsigned long time) 337b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 338dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* give the phy enabling interrupt event time to come in (1s 339dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik * is empirically about all it takes) */ 340dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (time < HZ) 341dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 342dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* Wait for discovery to finish */ 343dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik scsi_flush_work(shost); 344dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 1; 345b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 346b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 347dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_task_prep_smp(struct mvs_info *mvi, 348dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_task_exec_info *tei) 349b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 350dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int elem, rc, i; 351dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct sas_task *task = tei->task; 352dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_cmd_hdr *hdr = tei->hdr; 353dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct scatterlist *sg_req, *sg_resp; 354dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 req_len, resp_len, tag = tei->tag; 355dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik void *buf_tmp; 356dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u8 *buf_oaf; 357dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dma_addr_t buf_tmp_dma; 358dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_prd *buf_prd; 359dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct scatterlist *sg; 360dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_slot_info *slot = &mvi->slot_info[tag]; 361dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct asd_sas_port *sas_port = task->dev->port; 362dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT); 363dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#if _MV_DUMP 364dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u8 *buf_cmd; 365dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik void *from; 366dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif 367dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* 368dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik * DMA-map SMP request, response buffers 369dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik */ 370dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sg_req = &task->smp_task.smp_req; 371dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik elem = pci_map_sg(mvi->pdev, sg_req, 1, PCI_DMA_TODEVICE); 372dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!elem) 373dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return -ENOMEM; 374dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik req_len = sg_dma_len(sg_req); 375b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 376dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sg_resp = &task->smp_task.smp_resp; 377dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik elem = pci_map_sg(mvi->pdev, sg_resp, 1, PCI_DMA_FROMDEVICE); 378dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!elem) { 379dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = -ENOMEM; 380dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto err_out; 381dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 382dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik resp_len = sg_dma_len(sg_resp); 383b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 384dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* must be in dwords */ 385dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if ((req_len & 0x3) || (resp_len & 0x3)) { 386dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = -EINVAL; 387dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto err_out_2; 388b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 389b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 390dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* 391dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs 392dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik */ 393b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 394dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */ 395dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_tmp = slot->buf; 396dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_tmp_dma = slot->buf_dma; 397b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 398dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#if _MV_DUMP 399dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_cmd = buf_tmp; 400dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); 401dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_tmp += req_len; 402dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_tmp_dma += req_len; 403dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot->cmd_size = req_len; 404dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#else 405dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req)); 406dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif 407b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 408dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ 409dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_oaf = buf_tmp; 410dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->open_frame = cpu_to_le64(buf_tmp_dma); 411b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 412dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_tmp += MVS_OAF_SZ; 413dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_tmp_dma += MVS_OAF_SZ; 414b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 415dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* region 3: PRD table ********************************************* */ 416dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_prd = buf_tmp; 417dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (tei->n_elem) 418dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); 419dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik else 420dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->prd_tbl = 0; 421b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 422dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik i = sizeof(struct mvs_prd) * tei->n_elem; 423dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_tmp += i; 424dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_tmp_dma += i; 425b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 426dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ 427dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot->response = buf_tmp; 428dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->status_buf = cpu_to_le64(buf_tmp_dma); 429b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 430dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* 431dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik * Fill in TX ring and command slot header 432dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik */ 433dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot->tx = mvi->tx_prod; 434dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) | 435dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik TXQ_MODE_I | tag | 436dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik (sas_port->phy_mask << TXQ_PHY_SHIFT)); 437b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 438dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->flags |= flags; 439dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4)); 440dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->tags = cpu_to_le32(tag); 441dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->data_len = 0; 442b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 443dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* generate open address frame hdr (first 12 bytes) */ 444dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_oaf[0] = (1 << 7) | (0 << 4) | 0x01; /* initiator, SMP, ftype 1h */ 445dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_oaf[1] = task->dev->linkrate & 0xf; 446dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik *(u16 *)(buf_oaf + 2) = 0xFFFF; /* SAS SPEC */ 447dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE); 448dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 449dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* fill in PRD (scatter/gather) table, if any */ 450dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik for_each_sg(task->scatter, sg, tei->n_elem, i) { 451dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); 452dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_prd->len = cpu_to_le32(sg_dma_len(sg)); 453dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_prd++; 454b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 455b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 456dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#if _MV_DUMP 457dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* copy cmd table */ 458dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik from = kmap_atomic(sg_page(sg_req), KM_IRQ0); 459dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik memcpy(buf_cmd, from + sg_req->offset, req_len); 460dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik kunmap_atomic(from, KM_IRQ0); 461dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif 462b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 463b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 464dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out_2: 465dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_resp, 1, 466dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik PCI_DMA_FROMDEVICE); 467b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out: 468dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_req, 1, 469dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik PCI_DMA_TODEVICE); 470b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 4718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 4728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 473dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag) 4748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 475dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct ata_queued_cmd *qc = task->uldd_task; 4768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 477dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (qc) { 478dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (qc->tf.command == ATA_CMD_FPDMA_WRITE || 479dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik qc->tf.command == ATA_CMD_FPDMA_READ) { 480dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik *tag = qc->tag; 481dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 1; 482dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 4838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei } 4848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 485dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 4868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 4878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 488dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_task_prep_ata(struct mvs_info *mvi, 489dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_task_exec_info *tei) 490b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 491b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct sas_task *task = tei->task; 492b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct domain_device *dev = task->dev; 493b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_cmd_hdr *hdr = tei->hdr; 494b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct asd_sas_port *sas_port = dev->port; 4958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei struct mvs_slot_info *slot; 496b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct scatterlist *sg; 497b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_prd *buf_prd; 4988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei struct mvs_port *port = tei->port; 4998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u32 tag = tei->tag; 5008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT); 501b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void *buf_tmp; 502b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u8 *buf_cmd, *buf_oaf; 503b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dma_addr_t buf_tmp_dma; 5048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u32 i, req_len, resp_len; 5058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei const u32 max_resp_len = SB_RFB_MAX; 5068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 5078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei if (mvs_assign_reg_set(mvi, port) == MVS_ID_NOT_MAPPED) 5088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei return -EBUSY; 509b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 5108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei slot = &mvi->slot_info[tag]; 5118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei slot->tx = mvi->tx_prod; 5128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag | 5138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei (TXQ_CMD_STP << TXQ_CMD_SHIFT) | 5148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei (sas_port->phy_mask << TXQ_PHY_SHIFT) | 5158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei (port->taskfileset << TXQ_SRS_SHIFT)); 516b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 517b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (task->ata_task.use_ncq) 518b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik flags |= MCH_FPDMA; 5198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) { 5208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI) 5218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei flags |= MCH_ATAPI; 5228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei } 5238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 524b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* FIXME: fill in port multiplier number */ 525b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 526b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->flags = cpu_to_le32(flags); 5278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 5288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* FIXME: the low order order 5 bits for the TAG if enable NCQ */ 5294e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr->tags)) 5304e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei task->ata_task.fis.sector_count |= hdr->tags << 3; 5314e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei else 5328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei hdr->tags = cpu_to_le32(tag); 533b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->data_len = cpu_to_le32(task->total_xfer_len); 534b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 535b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* 536b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs 537b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 538b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 5398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */ 5408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei buf_cmd = buf_tmp = slot->buf; 541b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma = slot->buf_dma; 542b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 543b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); 544b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 545b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += MVS_ATA_CMD_SZ; 546b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += MVS_ATA_CMD_SZ; 5478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP 5488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei slot->cmd_size = MVS_ATA_CMD_SZ; 5498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif 550b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 5518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ 552b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* used for STP. unused for SATA? */ 553b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_oaf = buf_tmp; 554b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->open_frame = cpu_to_le64(buf_tmp_dma); 555b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 556b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += MVS_OAF_SZ; 557b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += MVS_OAF_SZ; 558b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 5598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* region 3: PRD table ********************************************* */ 560b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd = buf_tmp; 5618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei if (tei->n_elem) 5628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); 5638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei else 5648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei hdr->prd_tbl = 0; 565b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 566b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik i = sizeof(struct mvs_prd) * tei->n_elem; 567b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += i; 568b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += i; 569b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 5708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ 571b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* FIXME: probably unused, for SATA. kept here just in case 572b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * we get a STP/SATA error information record 573b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 574b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik slot->response = buf_tmp; 575b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->status_buf = cpu_to_le64(buf_tmp_dma); 576b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 5778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei req_len = sizeof(struct host_to_dev_fis); 578b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ - 5798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei sizeof(struct mvs_err_info) - i; 580b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 581b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* request, response lengths */ 5828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei resp_len = min(resp_len, max_resp_len); 583b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4)); 584b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 5858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */ 586b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* fill in command FIS and ATAPI CDB */ 5878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis)); 5888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) 5898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei memcpy(buf_cmd + STP_ATAPI_CMD, 5908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei task->ata_task.atapi_packet, 16); 5918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 5928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* generate open address frame hdr (first 12 bytes) */ 5938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei buf_oaf[0] = (1 << 7) | (2 << 4) | 0x1; /* initiator, STP, ftype 1h */ 5948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei buf_oaf[1] = task->dev->linkrate & 0xf; 5958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei *(u16 *)(buf_oaf + 2) = cpu_to_be16(tag); 5968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE); 597b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 598b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* fill in PRD (scatter/gather) table, if any */ 5998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei for_each_sg(task->scatter, sg, tei->n_elem, i) { 600b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); 601b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd->len = cpu_to_le32(sg_dma_len(sg)); 602b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd++; 603b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 604b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 605b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 606b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 607b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 608b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_task_prep_ssp(struct mvs_info *mvi, 609b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_task_exec_info *tei) 610b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 611b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct sas_task *task = tei->task; 612b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_cmd_hdr *hdr = tei->hdr; 6138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei struct mvs_port *port = tei->port; 614b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_slot_info *slot; 615b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct scatterlist *sg; 616b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_prd *buf_prd; 617b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct ssp_frame_hdr *ssp_hdr; 618b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void *buf_tmp; 619b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u8 *buf_cmd, *buf_oaf, fburst = 0; 620b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dma_addr_t buf_tmp_dma; 621b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 flags; 6228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u32 resp_len, req_len, i, tag = tei->tag; 6238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei const u32 max_resp_len = SB_RFB_MAX; 6244e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei u8 phy_mask; 625b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 626b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik slot = &mvi->slot_info[tag]; 627b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 6284e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei phy_mask = (port->wide_port_phymap) ? port->wide_port_phymap : 6294e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei task->dev->port->phy_mask; 6308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei slot->tx = mvi->tx_prod; 6318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag | 6328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei (TXQ_CMD_SSP << TXQ_CMD_SHIFT) | 6334e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei (phy_mask << TXQ_PHY_SHIFT)); 634b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 635b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik flags = MCH_RETRY; 636b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (task->ssp_task.enable_first_burst) { 637b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik flags |= MCH_FBURST; 638b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik fburst = (1 << 7); 639b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 640b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->flags = cpu_to_le32(flags | 6418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei (tei->n_elem << MCH_PRD_LEN_SHIFT) | 6428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT)); 643b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 644b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->tags = cpu_to_le32(tag); 645b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->data_len = cpu_to_le32(task->total_xfer_len); 646b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 647b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* 648b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs 649b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 650b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 6518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */ 6528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei buf_cmd = buf_tmp = slot->buf; 653b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma = slot->buf_dma; 654b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 655b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); 656b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 657b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += MVS_SSP_CMD_SZ; 658b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += MVS_SSP_CMD_SZ; 6598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP 6608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei slot->cmd_size = MVS_SSP_CMD_SZ; 6618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif 662b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 6638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ 664b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_oaf = buf_tmp; 665b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->open_frame = cpu_to_le64(buf_tmp_dma); 666b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 667b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += MVS_OAF_SZ; 668b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += MVS_OAF_SZ; 669b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 6708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* region 3: PRD table ********************************************* */ 671b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd = buf_tmp; 6728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei if (tei->n_elem) 6738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); 6748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei else 6758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei hdr->prd_tbl = 0; 676b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 677b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik i = sizeof(struct mvs_prd) * tei->n_elem; 678b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += i; 679b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += i; 680b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 6818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ 682b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik slot->response = buf_tmp; 683b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->status_buf = cpu_to_le64(buf_tmp_dma); 684b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 685b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ - 6868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei sizeof(struct mvs_err_info) - i; 6878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei resp_len = min(resp_len, max_resp_len); 6888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 6898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei req_len = sizeof(struct ssp_frame_hdr) + 28; 690b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 691b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* request, response lengths */ 692b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4)); 693b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 694b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* generate open address frame hdr (first 12 bytes) */ 695b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_oaf[0] = (1 << 7) | (1 << 4) | 0x1; /* initiator, SSP, ftype 1h */ 696b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_oaf[1] = task->dev->linkrate & 0xf; 6978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei *(u16 *)(buf_oaf + 2) = cpu_to_be16(tag); 698b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE); 699b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 7008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* fill in SSP frame header (Command Table.SSP frame header) */ 7018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei ssp_hdr = (struct ssp_frame_hdr *)buf_cmd; 702b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik ssp_hdr->frame_type = SSP_COMMAND; 703b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memcpy(ssp_hdr->hashed_dest_addr, task->dev->hashed_sas_addr, 704b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik HASHED_SAS_ADDR_SIZE); 705b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memcpy(ssp_hdr->hashed_src_addr, 706b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik task->dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); 707b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik ssp_hdr->tag = cpu_to_be16(tag); 708b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 709b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* fill in command frame IU */ 710b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_cmd += sizeof(*ssp_hdr); 711b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memcpy(buf_cmd, &task->ssp_task.LUN, 8); 7128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei buf_cmd[9] = fburst | task->ssp_task.task_attr | 7138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei (task->ssp_task.task_prio << 3); 714b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16); 715b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 716b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* fill in PRD (scatter/gather) table, if any */ 7178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei for_each_sg(task->scatter, sg, tei->n_elem, i) { 718b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); 719b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd->len = cpu_to_le32(sg_dma_len(sg)); 720b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd++; 721b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 722b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 723b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 724b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 725b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 726dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags) 727b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 7288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei struct domain_device *dev = task->dev; 7298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei struct mvs_info *mvi = dev->port->ha->lldd_ha; 7308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei struct pci_dev *pdev = mvi->pdev; 731b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void __iomem *regs = mvi->regs; 732b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_task_exec_info tei; 7338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei struct sas_task *t = task; 7344e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei struct mvs_slot_info *slot; 7358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u32 tag = 0xdeadbeef, rc, n_elem = 0; 7368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei unsigned long flags; 7378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u32 n = num, pass = 0; 738b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 7398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei spin_lock_irqsave(&mvi->lock, flags); 7408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei do { 7414e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei dev = t->dev; 7428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei tei.port = &mvi->port[dev->port->id]; 743b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 744dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!tei.port->port_attached) { 745dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (sas_protocol_ata(t->task_proto)) { 746dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = SAS_PHY_DOWN; 747dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto out_done; 748dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else { 749dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct task_status_struct *ts = &t->task_status; 750dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik ts->resp = SAS_TASK_UNDELIVERED; 751dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik ts->stat = SAS_PHY_DOWN; 752dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik t->task_done(t); 753dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (n > 1) 754dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik t = list_entry(t->list.next, 755dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct sas_task, list); 756dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik continue; 757dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 758dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 759dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 760dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!sas_protocol_ata(t->task_proto)) { 761dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (t->num_scatter) { 762dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik n_elem = pci_map_sg(mvi->pdev, t->scatter, 763dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik t->num_scatter, 764dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik t->data_dir); 765dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!n_elem) { 766dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = -ENOMEM; 767dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto err_out; 768dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 769dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 770dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else { 771dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik n_elem = t->num_scatter; 772dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 773dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 774dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = mvs_tag_alloc(mvi, &tag); 775dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (rc) 776dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto err_out; 777dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 778dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot = &mvi->slot_info[tag]; 779dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik t->lldd_task = NULL; 780dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot->n_elem = n_elem; 781dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik memset(slot->buf, 0, MVS_SLOT_BUF_SZ); 782dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tei.task = t; 783dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tei.hdr = &mvi->slot[tag]; 784dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tei.tag = tag; 785dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tei.n_elem = n_elem; 786dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 787dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik switch (t->task_proto) { 788dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SMP: 789dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = mvs_task_prep_smp(mvi, &tei); 790dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 791dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SSP: 792dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = mvs_task_prep_ssp(mvi, &tei); 793dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 794dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SATA: 795dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_STP: 796dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: 797dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = mvs_task_prep_ata(mvi, &tei); 798dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 799dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik default: 800dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 801dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik "unknown sas_task proto: 0x%x\n", 802dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik t->task_proto); 803dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = -EINVAL; 804dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 805dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 806dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 807dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (rc) 808dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto err_out_tag; 809dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 810dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot->task = t; 811dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot->port = tei.port; 812dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik t->lldd_task = (void *) slot; 813dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik list_add_tail(&slot->list, &slot->port->list); 814dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* TODO: select normal or high priority */ 815dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 816dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_lock(&t->task_state_lock); 817dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik t->task_state_flags |= SAS_TASK_AT_INITIATOR; 818dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_unlock(&t->task_state_lock); 819dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 820dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_hba_memory_dump(mvi, tag, t->task_proto); 821dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 822dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik ++pass; 823dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1); 824dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (n > 1) 825dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik t = list_entry(t->list.next, struct sas_task, list); 826dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } while (--n); 827dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 828dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = 0; 829dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto out_done; 830dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 831dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out_tag: 832dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_tag_free(mvi, tag); 833dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out: 834dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_ERR, &pdev->dev, "mvsas exec failed[%d]!\n", rc); 835dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!sas_protocol_ata(t->task_proto)) 836dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (n_elem) 837dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik pci_unmap_sg(mvi->pdev, t->scatter, n_elem, 838dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik t->data_dir); 839dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikout_done: 840dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (pass) 841dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mw32(TX_PROD_IDX, (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1)); 842dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_unlock_irqrestore(&mvi->lock, flags); 843dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return rc; 844dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 845dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 846dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc) 847dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 848dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 slot_idx = rx_desc & RXQ_SLOT_MASK; 849dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_tag_clear(mvi, slot_idx); 850dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 851dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 852dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task, 853dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_slot_info *slot, u32 slot_idx) 854dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 855dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!sas_protocol_ata(task->task_proto)) 856dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (slot->n_elem) 857dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik pci_unmap_sg(mvi->pdev, task->scatter, 858dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot->n_elem, task->data_dir); 859dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 860dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik switch (task->task_proto) { 861dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SMP: 862dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik pci_unmap_sg(mvi->pdev, &task->smp_task.smp_resp, 1, 863dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik PCI_DMA_FROMDEVICE); 864dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik pci_unmap_sg(mvi->pdev, &task->smp_task.smp_req, 1, 865dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik PCI_DMA_TODEVICE); 866dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 867dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 868dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SATA: 869dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_STP: 870dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SSP: 871dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik default: 872dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* do nothing */ 873dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 874dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 875dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik list_del(&slot->list); 876dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik task->lldd_task = NULL; 877dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot->task = NULL; 878dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot->port = NULL; 879dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 880dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 881dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_update_wideport(struct mvs_info *mvi, int i) 882dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 883dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_phy *phy = &mvi->phy[i]; 884dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_port *port = phy->port; 885dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int j, no; 886dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 887dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik for_each_phy(port->wide_port_phymap, no, j, mvi->chip->n_phy) 888dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (no & 1) { 889dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT); 890dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_cfg_data(mvi, no, 891dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik port->wide_port_phymap); 892dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else { 893dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT); 894dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_cfg_data(mvi, no, 0); 895dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 896dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 897dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 898dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_is_phy_ready(struct mvs_info *mvi, int i) 899dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 900dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 tmp; 901dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_phy *phy = &mvi->phy[i]; 902dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_port *port = phy->port;; 903dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 904dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp = mvs_read_phy_ctl(mvi, i); 905dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 906dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) { 907dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!port) 908dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->phy_attached = 1; 909dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return tmp; 910dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 911dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 912dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (port) { 913dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy->phy_type & PORT_TYPE_SAS) { 914dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik port->wide_port_phymap &= ~(1U << i); 915dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!port->wide_port_phymap) 916dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik port->port_attached = 0; 917dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_update_wideport(mvi, i); 918dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else if (phy->phy_type & PORT_TYPE_SATA) 919dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik port->port_attached = 0; 920dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_free_reg_set(mvi, phy->port); 921dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->port = NULL; 922dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->phy_attached = 0; 923dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); 924dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 925dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 926dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 927dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 928dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf) 929dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 930dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 *s = (u32 *) buf; 931dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 932dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!s) 933dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return NULL; 934dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 935dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3); 936dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik s[3] = mvs_read_port_cfg_data(mvi, i); 937dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 938dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2); 939dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik s[2] = mvs_read_port_cfg_data(mvi, i); 940dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 941dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1); 942dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik s[1] = mvs_read_port_cfg_data(mvi, i); 943dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 944dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0); 945dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik s[0] = mvs_read_port_cfg_data(mvi, i); 946dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 947dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return (void *)s; 948dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 949dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 950dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_is_sig_fis_received(u32 irq_status) 951dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 952dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return irq_status & PHYEV_SIG_FIS; 953dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 954dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 955dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_update_phyinfo(struct mvs_info *mvi, int i, 956dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int get_st) 957dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 958dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_phy *phy = &mvi->phy[i]; 959dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct pci_dev *pdev = mvi->pdev; 960dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 tmp; 961dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u64 tmp64; 962dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 963dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY); 964dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->dev_info = mvs_read_port_cfg_data(mvi, i); 9654e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei 966dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI); 967dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->dev_sas_addr = (u64) mvs_read_port_cfg_data(mvi, i) << 32; 968b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 969dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO); 970dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->dev_sas_addr |= mvs_read_port_cfg_data(mvi, i); 971b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 972dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (get_st) { 973dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->irq_status = mvs_read_port_irq_stat(mvi, i); 974dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->phy_status = mvs_is_phy_ready(mvi, i); 975dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 9768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 977dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy->phy_status) { 978dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 phy_st; 979dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i]; 980b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 981dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_cfg_addr(mvi, i, PHYR_PHY_STAT); 982dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy_st = mvs_read_port_cfg_data(mvi, i); 983b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 984dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sas_phy->linkrate = 985dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> 986dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET; 987dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->minimum_linkrate = 988dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik (phy->phy_status & 989dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik PHY_MIN_SPP_PHYS_LINK_RATE_MASK) >> 8; 990dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->maximum_linkrate = 991dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik (phy->phy_status & 992dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik PHY_MAX_SPP_PHYS_LINK_RATE_MASK) >> 12; 993b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 994dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy->phy_type & PORT_TYPE_SAS) { 995dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* Updated attached_sas_addr */ 996dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI); 997dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->att_dev_sas_addr = 998dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik (u64) mvs_read_port_cfg_data(mvi, i) << 32; 999dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO); 1000dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i); 1001dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO); 1002dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->att_dev_info = mvs_read_port_cfg_data(mvi, i); 1003dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->identify.device_type = 1004dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->att_dev_info & PORT_DEV_TYPE_MASK; 1005b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1006dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy->identify.device_type == SAS_END_DEV) 1007dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->identify.target_port_protocols = 1008dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik SAS_PROTOCOL_SSP; 1009dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik else if (phy->identify.device_type != NO_DEVICE) 1010dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->identify.target_port_protocols = 1011dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik SAS_PROTOCOL_SMP; 1012dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy_st & PHY_OOB_DTCTD) 1013dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sas_phy->oob_mode = SAS_OOB_MODE; 1014dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->frame_rcvd_size = 1015dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sizeof(struct sas_identify_frame); 1016dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else if (phy->phy_type & PORT_TYPE_SATA) { 1017dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->identify.target_port_protocols = SAS_PROTOCOL_STP; 1018dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (mvs_is_sig_fis_received(phy->irq_status)) { 1019dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->att_dev_sas_addr = i; /* temp */ 1020dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy_st & PHY_OOB_DTCTD) 1021dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sas_phy->oob_mode = SATA_OOB_MODE; 1022dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->frame_rcvd_size = 1023dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sizeof(struct dev_to_host_fis); 1024dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_get_d2h_reg(mvi, i, 1025dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik (void *)sas_phy->frame_rcvd); 1026dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else { 1027dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, 1028dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik "No sig fis\n"); 1029dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->phy_type &= ~(PORT_TYPE_SATA); 1030dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto out_done; 1031dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1032dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1033dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp64 = cpu_to_be64(phy->att_dev_sas_addr); 1034dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik memcpy(sas_phy->attached_sas_addr, &tmp64, SAS_ADDR_SIZE); 1035b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1036dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, 1037dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik "phy[%d] Get Attached Address 0x%llX ," 1038dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik " SAS Address 0x%llX\n", 1039dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik i, 1040dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik (unsigned long long)phy->att_dev_sas_addr, 1041dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik (unsigned long long)phy->dev_sas_addr); 1042dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, 1043dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik "Rate = %x , type = %d\n", 1044dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sas_phy->linkrate, phy->phy_type); 1045b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1046dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* workaround for HW phy decoding error on 1.5g disk drive */ 1047dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6); 1048dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp = mvs_read_port_vsr_data(mvi, i); 1049dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> 1050dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) == 1051dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik SAS_LINK_RATE_1_5_GBPS) 1052dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp &= ~PHY_MODE6_LATECLK; 1053dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik else 1054dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp |= PHY_MODE6_LATECLK; 1055dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_vsr_data(mvi, i, tmp); 1056b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1057dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 10584e52fc0a0a2ec2158691efba3f149f6416481255Ke Weiout_done: 1059dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (get_st) 1060dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_irq_stat(mvi, i, phy->irq_status); 1061b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1062b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1063dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikvoid mvs_port_formed(struct asd_sas_phy *sas_phy) 10648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 1065dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct sas_ha_struct *sas_ha = sas_phy->ha; 1066dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_info *mvi = sas_ha->lldd_ha; 1067dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct asd_sas_port *sas_port = sas_phy->port; 1068dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_phy *phy = sas_phy->lldd_phy; 1069dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_port *port = &mvi->port[sas_port->id]; 10708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei unsigned long flags; 10718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1072dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_lock_irqsave(&mvi->lock, flags); 1073dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik port->port_attached = 1; 1074dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->port = port; 1075dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik port->taskfileset = MVS_ID_NOT_MAPPED; 1076dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy->phy_type & PORT_TYPE_SAS) { 1077dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik port->wide_port_phymap = sas_port->phy_mask; 1078dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_update_wideport(mvi, sas_phy->id); 10798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei } 1080dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_unlock_irqrestore(&mvi->lock, flags); 1081dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 1082dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 1083dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_I_T_nexus_reset(struct domain_device *dev) 1084dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 1085dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return TMF_RESP_FUNC_FAILED; 1086dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 1087dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 1088dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task, 1089dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 slot_idx, int err) 1090dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 1091dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_port *port = mvi->slot_info[slot_idx].port; 1092dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct task_status_struct *tstat = &task->task_status; 1093dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf; 1094dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int stat = SAM_GOOD; 1095dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 1096dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik resp->frame_len = sizeof(struct dev_to_host_fis); 1097dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik memcpy(&resp->ending_fis[0], 1098dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik SATA_RECEIVED_D2H_FIS(port->taskfileset), 1099dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sizeof(struct dev_to_host_fis)); 1100dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tstat->buf_valid_size = sizeof(*resp); 1101dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (unlikely(err)) 1102dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik stat = SAS_PROTO_RESPONSE; 1103dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return stat; 1104dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 1105dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 1106dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task, 1107dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 slot_idx) 1108dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 1109dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; 1110dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response)); 1111dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 err_dw1 = le32_to_cpu(*(u32 *) (slot->response + 4)); 1112dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int stat = SAM_CHECK_COND; 11138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1114dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (err_dw1 & SLOT_BSY_ERR) { 1115dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik stat = SAS_QUEUE_FULL; 1116dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_slot_reset(mvi, task, slot_idx); 1117dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 11188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei switch (task->task_proto) { 11198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei case SAS_PROTOCOL_SSP: 1120dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 1121dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SMP: 11228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei break; 11238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei case SAS_PROTOCOL_SATA: 11248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei case SAS_PROTOCOL_STP: 1125dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: 1126dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (err_dw0 & TFILE_ERR) 1127dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik stat = mvs_sata_done(mvi, task, slot_idx, 1); 11288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei break; 11298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei default: 11308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei break; 11318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei } 11328121ed420285885654af133a6ca1919590f98917Ke Wei 1133dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_hexdump(16, (u8 *) slot->response, 0); 1134dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return stat; 11358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 11368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1137dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) 1138b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1139dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 slot_idx = rx_desc & RXQ_SLOT_MASK; 1140dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; 1141dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct sas_task *task = slot->task; 1142dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct task_status_struct *tstat; 1143dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_port *port; 1144dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik bool aborted; 1145dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik void *to; 1146b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1147dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (unlikely(!task || !task->lldd_task)) 1148dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return -1; 1149b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1150dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_hba_cq_dump(mvi); 1151b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1152dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_lock(&task->task_state_lock); 1153dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED; 1154dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!aborted) { 1155dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik task->task_state_flags &= 1156dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); 1157dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik task->task_state_flags |= SAS_TASK_STATE_DONE; 1158b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1159dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_unlock(&task->task_state_lock); 1160b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1161dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (aborted) { 1162dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_slot_task_free(mvi, task, slot, slot_idx); 1163dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_slot_free(mvi, rx_desc); 1164dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return -1; 1165dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1166b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1167dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik port = slot->port; 1168dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tstat = &task->task_status; 1169dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik memset(tstat, 0, sizeof(*tstat)); 1170dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tstat->resp = SAS_TASK_COMPLETE; 1171b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1172dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (unlikely(!port->port_attached || flags)) { 1173dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_slot_err(mvi, task, slot_idx); 1174dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!sas_protocol_ata(task->task_proto)) 1175dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tstat->stat = SAS_PHY_DOWN; 1176dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto out; 1177dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1178b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1179dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* error info record present */ 1180dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) { 1181dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tstat->stat = mvs_slot_err(mvi, task, slot_idx); 1182dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto out; 1183dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1184b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1185dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik switch (task->task_proto) { 1186dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SSP: 1187dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* hw says status == 0, datapres == 0 */ 1188dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (rx_desc & RXQ_GOOD) { 1189dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tstat->stat = SAM_GOOD; 1190dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tstat->resp = SAS_TASK_COMPLETE; 1191dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1192dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* response frame present */ 1193dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik else if (rx_desc & RXQ_RSP) { 1194dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct ssp_response_iu *iu = 1195dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot->response + sizeof(struct mvs_err_info); 1196dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sas_ssp_task_response(&mvi->pdev->dev, task, iu); 1197dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1198b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1199dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* should never happen? */ 1200dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik else 1201dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tstat->stat = SAM_CHECK_COND; 1202dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 1203dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 1204dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SMP: { 1205dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct scatterlist *sg_resp = &task->smp_task.smp_resp; 1206dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tstat->stat = SAM_GOOD; 1207dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik to = kmap_atomic(sg_page(sg_resp), KM_IRQ0); 1208dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik memcpy(to + sg_resp->offset, 1209dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot->response + sizeof(struct mvs_err_info), 1210dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sg_dma_len(sg_resp)); 1211dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik kunmap_atomic(to, KM_IRQ0); 12128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei break; 1213b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1214b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1215dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SATA: 1216dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_STP: 1217dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: { 1218dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0); 1219b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 1220dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1221b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1222b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik default: 1223dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tstat->stat = SAM_CHECK_COND; 1224dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 1225b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1226b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1227dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikout: 1228dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_slot_task_free(mvi, task, slot, slot_idx); 1229dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (unlikely(tstat->stat != SAS_QUEUE_FULL)) 1230dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_slot_free(mvi, rx_desc); 1231b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1232dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_unlock(&mvi->lock); 1233dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik task->task_done(task); 1234dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_lock(&mvi->lock); 1235dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return tstat->stat; 1236b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1237b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1238dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_release_task(struct mvs_info *mvi, int phy_no) 1239b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1240dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct list_head *pos, *n; 1241dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_slot_info *slot; 1242dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_phy *phy = &mvi->phy[phy_no]; 1243dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_port *port = phy->port; 1244dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 rx_desc; 1245b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1246dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!port) 1247dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return; 1248b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1249dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik list_for_each_safe(pos, n, &port->list) { 1250dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot = container_of(pos, struct mvs_slot_info, list); 1251dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rx_desc = (u32) (slot - mvi->slot_info); 1252dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_slot_complete(mvi, rx_desc, 1); 1253b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1254dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 1255b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1256dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events) 1257dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 1258dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct pci_dev *pdev = mvi->pdev; 1259dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct sas_ha_struct *sas_ha = &mvi->sas; 1260dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_phy *phy = &mvi->phy[phy_no]; 1261dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct asd_sas_phy *sas_phy = &phy->sas_phy; 1262b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1263dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->irq_status = mvs_read_port_irq_stat(mvi, phy_no); 1264b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* 1265dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik * events is port event now , 1266dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik * we need check the interrupt status which belongs to per port. 1267dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik */ 1268dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, 1269dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik "Port %d Event = %X\n", 1270dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy_no, phy->irq_status); 1271b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1272dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy->irq_status & (PHYEV_POOF | PHYEV_DEC_ERR)) { 1273dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_release_task(mvi, phy_no); 1274dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!mvs_is_phy_ready(mvi, phy_no)) { 1275dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sas_phy_disconnected(sas_phy); 1276dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL); 1277dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 1278dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik "Port %d Unplug Notice\n", phy_no); 1279b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1280dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else 1281dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET, NULL); 1282b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1283dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!(phy->irq_status & PHYEV_DEC_ERR)) { 1284dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy->irq_status & PHYEV_COMWAKE) { 1285dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 tmp = mvs_read_port_irq_mask(mvi, phy_no); 1286dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_irq_mask(mvi, phy_no, 1287dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp | PHYEV_SIG_FIS); 1288dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1289dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) { 1290dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->phy_status = mvs_is_phy_ready(mvi, phy_no); 1291dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy->phy_status) { 1292dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_detect_porttype(mvi, phy_no); 1293b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1294dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy->phy_type & PORT_TYPE_SATA) { 1295dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 tmp = mvs_read_port_irq_mask(mvi, 1296dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy_no); 1297dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp &= ~PHYEV_SIG_FIS; 1298dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_irq_mask(mvi, 1299dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy_no, tmp); 1300dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1301b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1302dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_update_phyinfo(mvi, phy_no, 0); 1303dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sas_ha->notify_phy_event(sas_phy, 1304dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik PHYE_OOB_DONE); 1305dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_bytes_dmaed(mvi, phy_no); 1306dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else { 1307dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, 1308dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik "plugin interrupt but phy is gone\n"); 1309dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET, 1310dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik NULL); 1311dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1312dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else if (phy->irq_status & PHYEV_BROAD_CH) { 1313dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_release_task(mvi, phy_no); 1314dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sas_ha->notify_port_event(sas_phy, 1315dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik PORTE_BROADCAST_RCVD); 1316dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1317dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1318dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_write_port_irq_stat(mvi, phy_no, phy->irq_status); 1319b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1320b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1321dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_int_rx(struct mvs_info *mvi, bool self_clear) 1322b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1323b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void __iomem *regs = mvi->regs; 1324dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 rx_prod_idx, rx_desc; 1325dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik bool attn = false; 1326dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct pci_dev *pdev = mvi->pdev; 13278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1328dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* the first dword in the RX ring is special: it contains 1329dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik * a mirror of the hardware's RX producer index, so that 1330dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik * we don't have to stall the CPU reading that register. 1331dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik * The actual RX ring is offset by one dword, due to this. 1332dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik */ 1333dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rx_prod_idx = mvi->rx_cons; 1334dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvi->rx_cons = le32_to_cpu(mvi->rx[0]); 1335dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (mvi->rx_cons == 0xfff) /* h/w hasn't touched RX ring yet */ 1336dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 13378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1338dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* The CMPL_Q may come late, read from register and try again 1339dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik * note: if coalescing is enabled, 1340dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik * it will need to read from register every time for sure 1341dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik */ 1342dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (mvi->rx_cons == rx_prod_idx) 1343dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvi->rx_cons = mr32(RX_CONS_IDX) & RX_RING_SZ_MASK; 13448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1345dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (mvi->rx_cons == rx_prod_idx) 1346dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 13478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1348dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik while (mvi->rx_cons != rx_prod_idx) { 13498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1350dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* increment our internal RX consumer pointer */ 1351dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1); 13528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1353dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]); 13548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1355dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (likely(rx_desc & RXQ_DONE)) 1356dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_slot_complete(mvi, rx_desc, 0); 1357dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (rx_desc & RXQ_ATTN) { 1358dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik attn = true; 1359dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "ATTN %X\n", 1360dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rx_desc); 1361dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else if (rx_desc & RXQ_ERR) { 1362dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!(rx_desc & RXQ_DONE)) 1363dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_slot_complete(mvi, rx_desc, 0); 1364dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "RXQ_ERR %X\n", 1365dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rx_desc); 1366dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else if (rx_desc & RXQ_SLOT_RESET) { 1367dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "Slot reset[%X]\n", 1368dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rx_desc); 1369dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_slot_free(mvi, rx_desc); 1370dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1371dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 13728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1373dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (attn && self_clear) 1374dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_int_full(mvi); 13758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1376dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 13778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 13788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1379dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#ifndef MVS_DISABLE_NVRAM 1380dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_eep_read(void __iomem *regs, u32 addr, u32 *data) 13818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 1382dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int timeout = 1000; 1383b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1384dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (addr & ~SPI_ADDR_MASK) 1385dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return -EINVAL; 1386b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1387dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik writel(addr, regs + SPI_CMD); 1388dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik writel(TWSI_RD, regs + SPI_CTL); 1389b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1390dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik while (timeout-- > 0) { 1391dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (readl(regs + SPI_CTL) & TWSI_RDY) { 1392dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik *data = readl(regs + SPI_DATA); 1393dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 1394dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1395b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1396dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik udelay(10); 1397dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1398b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1399dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return -EBUSY; 1400dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 1401b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1402dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_eep_read_buf(void __iomem *regs, u32 addr, 1403dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik void *buf, u32 buflen) 1404dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 1405dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 addr_end, tmp_addr, i, j; 1406dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 tmp = 0; 1407dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int rc; 1408dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u8 *tmp8, *buf8 = buf; 1409b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1410dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik addr_end = addr + buflen; 1411dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp_addr = ALIGN(addr, 4); 1412dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (addr > 0xff) 1413dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return -EINVAL; 1414b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1415dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik j = addr & 0x3; 1416dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (j) { 1417dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = mvs_eep_read(regs, tmp_addr, &tmp); 1418dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (rc) 1419dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return rc; 1420b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1421dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp8 = (u8 *)&tmp; 1422dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik for (i = j; i < 4; i++) 1423dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik *buf8++ = tmp8[i]; 14248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1425dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp_addr += 4; 1426dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 14278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1428dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik for (j = ALIGN(addr_end, 4); tmp_addr < j; tmp_addr += 4) { 1429dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = mvs_eep_read(regs, tmp_addr, &tmp); 1430dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (rc) 1431dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return rc; 14328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1433dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik memcpy(buf8, &tmp, 4); 1434dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf8 += 4; 1435dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 14368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1437dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (tmp_addr < addr_end) { 1438dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = mvs_eep_read(regs, tmp_addr, &tmp); 1439dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (rc) 1440dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return rc; 14418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1442dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp8 = (u8 *)&tmp; 1443dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik j = addr_end - tmp_addr; 1444dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik for (i = 0; i < j; i++) 1445dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik *buf8++ = tmp8[i]; 14468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1447dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp_addr += 4; 1448dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 14498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1450dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 14518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 1452dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif 14538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1454dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_nvram_read(struct mvs_info *mvi, u32 addr, void *buf, u32 buflen) 14558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 1456dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#ifndef MVS_DISABLE_NVRAM 14578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei void __iomem *regs = mvi->regs; 1458dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int rc, i; 1459dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 sum; 1460dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u8 hdr[2], *tmp; 1461dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik const char *msg; 14628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1463dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = mvs_eep_read_buf(regs, addr, &hdr, 2); 1464dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (rc) { 1465dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik msg = "nvram hdr read failed"; 1466dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto err_out; 1467dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1468dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = mvs_eep_read_buf(regs, addr + 2, buf, buflen); 1469dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (rc) { 1470dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik msg = "nvram read failed"; 1471dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto err_out; 1472dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 14738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1474dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (hdr[0] != 0x5A) { 1475dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* entry id */ 1476dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik msg = "invalid nvram entry id"; 1477dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = -ENOENT; 1478dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto err_out; 1479dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 14808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1481dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp = buf; 1482dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sum = ((u32)hdr[0]) + ((u32)hdr[1]); 1483dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik for (i = 0; i < buflen; i++) 1484dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sum += ((u32)tmp[i]); 14858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1486dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (sum) { 1487dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik msg = "nvram checksum failure"; 1488dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = -EILSEQ; 1489dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto err_out; 1490dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 14918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1492dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 14938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1494dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out: 1495dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg); 1496dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return rc; 1497dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#else 1498dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* FIXME , For SAS target mode */ 1499dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8); 1500dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 1501dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif 15028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 15038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1504dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_int_sata(struct mvs_info *mvi) 15058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 1506dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 tmp; 1507dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik void __iomem *regs = mvi->regs; 1508dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp = mr32(INT_STAT_SRS); 1509dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mw32(INT_STAT_SRS, tmp & 0xFFFF); 15108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 15118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1512dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_slot_reset(struct mvs_info *mvi, struct sas_task *task, 1513dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 slot_idx) 15148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 1515dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik void __iomem *regs = mvi->regs; 1516dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct domain_device *dev = task->dev; 1517dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct asd_sas_port *sas_port = dev->port; 1518dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_port *port = mvi->slot_info[slot_idx].port; 1519dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 reg_set, phy_mask; 15208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1521dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!sas_protocol_ata(task->task_proto)) { 1522dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik reg_set = 0; 1523dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy_mask = (port->wide_port_phymap) ? port->wide_port_phymap : 1524dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sas_port->phy_mask; 1525dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else { 1526dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik reg_set = port->taskfileset; 1527dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy_mask = sas_port->phy_mask; 15288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei } 1529dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | slot_idx | 1530dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik (TXQ_CMD_SLOT_RESET << TXQ_CMD_SHIFT) | 1531dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik (phy_mask << TXQ_PHY_SHIFT) | 1532dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik (reg_set << TXQ_SRS_SHIFT)); 1533dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 1534dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mw32(TX_PROD_IDX, mvi->tx_prod); 1535dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1); 15368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 15378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1538dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikvoid mvs_int_full(struct mvs_info *mvi) 15398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 1540dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik void __iomem *regs = mvi->regs; 1541dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 tmp, stat; 1542dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int i; 15438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1544dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik stat = mr32(INT_STAT); 15458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1546dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_int_rx(mvi, false); 15478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1548dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik for (i = 0; i < MVS_MAX_PORTS; i++) { 1549dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED); 1550dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (tmp) 1551dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_int_port(mvi, i, tmp); 15528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei } 15538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1554dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (stat & CINT_SRS) 1555dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_int_sata(mvi); 15568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1557dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mw32(INT_STAT, stat); 1558dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 15598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1560dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#ifndef MVS_DISABLE_MSI 1561dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic irqreturn_t mvs_msi_interrupt(int irq, void *opaque) 1562dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 1563dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_info *mvi = opaque; 1564e9ff91b6927079307b5d481a93beac4134e923ebKe Wei 1565dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#ifndef MVS_USE_TASKLET 1566dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_lock(&mvi->lock); 1567e9ff91b6927079307b5d481a93beac4134e923ebKe Wei 1568dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_int_rx(mvi, true); 15698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1570dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_unlock(&mvi->lock); 1571dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#else 1572dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tasklet_schedule(&mvi->tasklet); 1573dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif 1574dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return IRQ_HANDLED; 15758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 1576dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif 15778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1578dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_task_abort(struct sas_task *task) 15798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 1580dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int rc; 15818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei unsigned long flags; 1582dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_info *mvi = task->dev->port->ha->lldd_ha; 1583dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct pci_dev *pdev = mvi->pdev; 1584dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int tag; 15858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1586dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_lock_irqsave(&task->task_state_lock, flags); 1587dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (task->task_state_flags & SAS_TASK_STATE_DONE) { 1588dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = TMF_RESP_FUNC_COMPLETE; 1589dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_unlock_irqrestore(&task->task_state_lock, flags); 1590dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto out_done; 15918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei } 1592dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_unlock_irqrestore(&task->task_state_lock, flags); 1593b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1594dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik switch (task->task_proto) { 1595dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SMP: 1596dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "SMP Abort! \n"); 1597dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 1598dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SSP: 1599dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "SSP Abort! \n"); 1600dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 1601dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SATA: 1602dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_STP: 1603dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:{ 1604dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "STP Abort! \n"); 1605dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#if _MV_DUMP 1606dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "Dump D2H FIS: \n"); 1607dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_hexdump(sizeof(struct host_to_dev_fis), 1608dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik (void *)&task->ata_task.fis, 0); 1609dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "Dump ATAPI Cmd : \n"); 1610dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_hexdump(16, task->ata_task.atapi_packet, 0); 1611dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif 1612dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_lock_irqsave(&task->task_state_lock, flags); 1613dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) { 1614dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* TODO */ 1615dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik ; 1616dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1617dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_unlock_irqrestore(&task->task_state_lock, flags); 1618dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 1619dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1620dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik default: 1621dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 1622dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1623dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 1624dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (mvs_find_tag(mvi, task, &tag)) { 1625dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_lock_irqsave(&mvi->lock, flags); 1626dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_slot_task_free(mvi, task, &mvi->slot_info[tag], tag); 1627dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik spin_unlock_irqrestore(&mvi->lock, flags); 1628dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1629dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!mvs_task_exec(task, 1, GFP_ATOMIC)) 1630dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = TMF_RESP_FUNC_COMPLETE; 1631dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik else 1632dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = TMF_RESP_FUNC_FAILED; 1633dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikout_done: 1634dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return rc; 1635e9ff91b6927079307b5d481a93beac4134e923ebKe Wei} 1636e9ff91b6927079307b5d481a93beac4134e923ebKe Wei 1637dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint __devinit mvs_hw_init(struct mvs_info *mvi) 1638b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1639b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void __iomem *regs = mvi->regs; 1640b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik int i; 1641b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 tmp, cctl; 1642b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1643b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* make sure interrupts are masked immediately (paranoia) */ 1644b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(GBL_CTL, 0); 1645b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp = mr32(GBL_CTL); 1646b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 16478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* Reset Controller */ 1648b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!(tmp & HBA_RST)) { 1649b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (mvi->flags & MVF_PHY_PWR_FIX) { 1650b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp); 1651b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp &= ~PCTL_PWR_ON; 1652b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp |= PCTL_OFF; 1653b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); 1654b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1655b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp); 1656b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp &= ~PCTL_PWR_ON; 1657b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp |= PCTL_OFF; 1658b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); 1659b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1660b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1661b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* global reset, incl. COMRESET/H_RESET_N (self-clearing) */ 1662b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32_f(GBL_CTL, HBA_RST); 1663b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1664b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1665b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* wait for reset to finish; timeout is just a guess */ 1666b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik i = 1000; 1667b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik while (i-- > 0) { 1668b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik msleep(10); 1669b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1670b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!(mr32(GBL_CTL) & HBA_RST)) 1671b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 1672b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1673b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (mr32(GBL_CTL) & HBA_RST) { 1674b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dev_printk(KERN_ERR, &mvi->pdev->dev, "HBA reset failed\n"); 1675b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return -EBUSY; 1676b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1677b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 16788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* Init Chip */ 1679b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* make sure RST is set; HBA_RST /should/ have done that for us */ 1680b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik cctl = mr32(CTL); 1681b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (cctl & CCTL_RST) 1682b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik cctl &= ~CCTL_RST; 1683b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik else 1684b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32_f(CTL, cctl | CCTL_RST); 1685b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 16868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* write to device control _AND_ device status register? - A.C. */ 16878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp); 16888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei tmp &= ~PRD_REQ_MASK; 16898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei tmp |= PRD_REQ_SIZE; 16908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp); 16918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1692b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp); 1693b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp |= PCTL_PWR_ON; 1694b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp &= ~PCTL_OFF; 1695b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); 1696b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1697b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp); 1698b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp |= PCTL_PWR_ON; 1699b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp &= ~PCTL_OFF; 1700b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); 1701b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1702b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32_f(CTL, cctl); 1703b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 17048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* reset control */ 17058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mw32(PCS, 0); /*MVS_PCS */ 17068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1707b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_phy_hacks(mvi); 1708b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1709b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(CMD_LIST_LO, mvi->slot_dma); 1710b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16); 1711b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1712b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(RX_FIS_LO, mvi->rx_fis_dma); 1713b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16); 1714b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 17158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mw32(TX_CFG, MVS_CHIP_SLOT_SZ); 1716b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(TX_LO, mvi->tx_dma); 1717b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(TX_HI, (mvi->tx_dma >> 16) >> 16); 1718b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1719b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(RX_CFG, MVS_RX_RING_SZ); 1720b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(RX_LO, mvi->rx_dma); 1721b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(RX_HI, (mvi->rx_dma >> 16) >> 16); 1722b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 17238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* enable auto port detection */ 17248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mw32(GBL_PORT_TYPE, MODE_AUTO_DET_EN); 1725ddccf307a3599e452804e228d8ed30fba578923eReinhard Nissl msleep(1100); 1726b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* init and reset phys */ 1727b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik for (i = 0; i < mvi->chip->n_phy; i++) { 172800da714b31b944400ee789e477f58247cff30b1bKe Wei u32 lo = be32_to_cpu(*(u32 *)&mvi->sas_addr[4]); 172900da714b31b944400ee789e477f58247cff30b1bKe Wei u32 hi = be32_to_cpu(*(u32 *)&mvi->sas_addr[0]); 17308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 17318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_detect_porttype(mvi, i); 1732b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1733b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* set phy local SAS address */ 17348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO); 17358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_write_port_cfg_data(mvi, i, lo); 17368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI); 17378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_write_port_cfg_data(mvi, i, hi); 1738b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1739b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* reset phy */ 17408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei tmp = mvs_read_phy_ctl(mvi, i); 1741b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp |= PHY_RST; 17428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_write_phy_ctl(mvi, i, tmp); 1743b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1744b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1745b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik msleep(100); 1746b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1747b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik for (i = 0; i < mvi->chip->n_phy; i++) { 17488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* clear phy int status */ 17498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei tmp = mvs_read_port_irq_stat(mvi, i); 17508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei tmp &= ~PHYEV_SIG_FIS; 17518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_write_port_irq_stat(mvi, i, tmp); 17528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1753b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* set phy int mask */ 17548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS | 17558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei PHYEV_ID_DONE | PHYEV_DEC_ERR; 17568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_write_port_irq_mask(mvi, i, tmp); 1757b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 17588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei msleep(100); 17598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_update_phyinfo(mvi, i, 1); 17608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvs_enable_xmt(mvi, i); 1761b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1762b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1763b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* FIXME: update wide port bitmaps */ 1764b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 17658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* little endian for open address and command table, etc. */ 17668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* A.C. 17678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei * it seems that ( from the spec ) turning on big-endian won't 17688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei * do us any good on big-endian machines, need further confirmation 17698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei */ 17708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei cctl = mr32(CTL); 17718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei cctl |= CCTL_ENDIAN_CMD; 17728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei cctl |= CCTL_ENDIAN_DATA; 17738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei cctl &= ~CCTL_ENDIAN_OPEN; 17748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei cctl |= CCTL_ENDIAN_RSP; 17758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mw32_f(CTL, cctl); 17768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 17778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* reset CMD queue */ 17788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei tmp = mr32(PCS); 17798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei tmp |= PCS_CMD_RST; 17808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mw32(PCS, tmp); 17818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* interrupt coalescing may cause missing HW interrput in some case, 17828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei * and the max count is 0x1ff, while our max slot is 0x200, 17838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei * it will make count 0. 17848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei */ 17858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei tmp = 0; 17868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mw32(INT_COAL, tmp); 17878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 17888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei tmp = 0x100; 17898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mw32(INT_COAL_TMOUT, tmp); 17908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1791b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* ladies and gentlemen, start your engines */ 17928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mw32(TX_CFG, 0); 17938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mw32(TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN); 1794b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(RX_CFG, MVS_RX_RING_SZ | RX_EN); 17958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* enable CMD/CMPL_Q/RESP mode */ 17968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mw32(PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | PCS_CMD_EN); 1797b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 17988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* enable completion queue interrupt */ 1799e9ff91b6927079307b5d481a93beac4134e923ebKe Wei tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS); 18008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mw32(INT_MASK, tmp); 1801b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1802e9ff91b6927079307b5d481a93beac4134e923ebKe Wei /* Enable SRS interrupt */ 1803e9ff91b6927079307b5d481a93beac4134e923ebKe Wei mw32(INT_MASK_SRS, 0xFF); 1804b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 1805b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1806b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1807dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikvoid __devinit mvs_print_info(struct mvs_info *mvi) 1808b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1809b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct pci_dev *pdev = mvi->pdev; 1810b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik static int printed_version; 1811b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1812b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!printed_version++) 1813b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); 1814b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1815b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dev_printk(KERN_INFO, &pdev->dev, "%u phys, addr %llx\n", 1816b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->chip->n_phy, SAS_ADDR(mvi->sas_addr)); 1817b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1818b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1819