mv_sas.c revision b5762948263dd5e9725a380e7a9626f99e40ae9d
1b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* 2b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvsas.c - Marvell 88SE6440 SAS/SATA support 3b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 4b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik Copyright 2007 Red Hat, Inc. 5b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 6b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik This program is free software; you can redistribute it and/or 7b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik modify it under the terms of the GNU General Public License as 8b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik published by the Free Software Foundation; either version 2, 9b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik or (at your option) any later version. 10b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 11b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik This program is distributed in the hope that it will be useful, 12b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik but WITHOUT ANY WARRANTY; without even the implied warranty 13b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik See the GNU General Public License for more details. 15b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 16b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik You should have received a copy of the GNU General Public 17b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik License along with this program; see the file COPYING. If not, 18b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik write to the Free Software Foundation, 675 Mass Ave, Cambridge, 19b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MA 02139, USA. 20b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 21b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik --------------------------------------------------------------- 22b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 23b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik Random notes: 24b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * hardware supports controlling the endian-ness of data 25b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik structures. this permits elimination of all the le32_to_cpu() 26b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik and cpu_to_le32() conversions. 27b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 28b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 29b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 30b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/kernel.h> 31b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/module.h> 32b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/pci.h> 33b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/interrupt.h> 34b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/spinlock.h> 35b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/delay.h> 36b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/dma-mapping.h> 37b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <scsi/libsas.h> 38b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <asm/io.h> 39b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 40b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#define DRV_NAME "mvsas" 41b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#define DRV_VERSION "0.1" 42b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 43b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#define mr32(reg) readl(regs + MVS_##reg) 44b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#define mw32(reg,val) writel((val), regs + MVS_##reg) 45b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#define mw32_f(reg,val) do { \ 46b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik writel((val), regs + MVS_##reg); \ 47b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik readl(regs + MVS_##reg); \ 48b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } while (0) 49b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 50b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* driver compile-time configuration */ 51b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum driver_configuration { 52b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_TX_RING_SZ = 1024, /* TX ring size (12-bit) */ 53b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_RX_RING_SZ = 1024, /* RX ring size (12-bit) */ 54b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* software requires power-of-2 55b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik ring size */ 56b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 57b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_SLOTS = 512, /* command slots */ 58b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_SLOT_BUF_SZ = 8192, /* cmd tbl + IU + status + PRD */ 59b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_SSP_CMD_SZ = 64, /* SSP command table buffer size */ 60b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_ATA_CMD_SZ = 128, /* SATA command table buffer size */ 61b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_OAF_SZ = 64, /* Open address frame buffer size */ 62b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 63b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_RX_FIS_COUNT = 17, /* Optional rx'd FISs (max 17) */ 64b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 65b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 66b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* unchangeable hardware details */ 67b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum hardware_details { 68b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_MAX_PHYS = 8, /* max. possible phys */ 69b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_MAX_PORTS = 8, /* max. possible ports */ 70b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_RX_FISL_SZ = 0x400 + (MVS_RX_FIS_COUNT * 0x100), 71b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 72b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 73b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* peripheral registers (BAR2) */ 74b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum peripheral_registers { 75b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik SPI_CTL = 0x10, /* EEPROM control */ 76b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik SPI_CMD = 0x14, /* EEPROM command */ 77b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik SPI_DATA = 0x18, /* EEPROM data */ 78b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 79b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 80b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum peripheral_register_bits { 81b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TWSI_RDY = (1U << 7), /* EEPROM interface ready */ 82b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TWSI_RD = (1U << 4), /* EEPROM read access */ 83b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 84b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik SPI_ADDR_MASK = 0x3ffff, /* bits 17:0 */ 85b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 86b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 87b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* enhanced mode registers (BAR4) */ 88b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum hw_registers { 89b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_GBL_CTL = 0x04, /* global control */ 90b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_GBL_INT_STAT = 0x08, /* global irq status */ 91b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_GBL_PI = 0x0C, /* ports implemented bitmask */ 92b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_GBL_PORT_TYPE = 0x00, /* port type */ 93b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 94b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_CTL = 0x100, /* SAS/SATA port configuration */ 95b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_PCS = 0x104, /* SAS/SATA port control/status */ 96b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_CMD_LIST_LO = 0x108, /* cmd list addr */ 97b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_CMD_LIST_HI = 0x10C, 98b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_RX_FIS_LO = 0x110, /* RX FIS list addr */ 99b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_RX_FIS_HI = 0x114, 100b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 101b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_TX_CFG = 0x120, /* TX configuration */ 102b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_TX_LO = 0x124, /* TX (delivery) ring addr */ 103b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_TX_HI = 0x128, 104b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 105b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_RX_PROD_IDX = 0x12C, /* RX producer pointer */ 106b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_RX_CONS_IDX = 0x130, /* RX consumer pointer (RO) */ 107b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_RX_CFG = 0x134, /* RX configuration */ 108b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_RX_LO = 0x138, /* RX (completion) ring addr */ 109b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_RX_HI = 0x13C, 110b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 111b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_INT_COAL = 0x148, /* Int coalescing config */ 112b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_INT_COAL_TMOUT = 0x14C, /* Int coalescing timeout */ 113b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_INT_STAT = 0x150, /* Central int status */ 114b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_INT_MASK = 0x154, /* Central int enable */ 115b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_INT_STAT_SRS = 0x158, /* SATA register set status */ 116b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 117b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* ports 1-3 follow after this */ 118b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_P0_INT_STAT = 0x160, /* port0 interrupt status */ 119b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_P0_INT_MASK = 0x164, /* port0 interrupt mask */ 120b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 121b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* ports 1-3 follow after this */ 122b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_P0_SER_CTLSTAT = 0x180, /* port0 serial control/status */ 123b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 124b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_CMD_ADDR = 0x1B8, /* Command register port (addr) */ 125b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_CMD_DATA = 0x1BC, /* Command register port (data) */ 126b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 127b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* ports 1-3 follow after this */ 128b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_P0_CFG_ADDR = 0x1C0, /* port0 phy register address */ 129b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVS_P0_CFG_DATA = 0x1C4, /* port0 phy register data */ 130b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 131b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 132b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum hw_register_bits { 133b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* MVS_GBL_CTL */ 134b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik INT_EN = (1U << 1), /* Global int enable */ 135b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik HBA_RST = (1U << 0), /* HBA reset */ 136b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 137b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* MVS_GBL_INT_STAT */ 138b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik INT_XOR = (1U << 4), /* XOR engine event */ 139b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik INT_SAS_SATA = (1U << 0), /* SAS/SATA event */ 140b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 141b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* MVS_GBL_PORT_TYPE */ /* shl for ports 1-3 */ 142b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik SATA_TARGET = (1U << 16), /* port0 SATA target enable */ 143b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik AUTO_DET = (1U << 8), /* port0 SAS/SATA autodetect */ 144b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik SAS_MODE = (1U << 0), /* port0 SAS(1), SATA(0) mode */ 145b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* SAS_MODE value may be 146b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * dictated (in hw) by values 147b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * of SATA_TARGET & AUTO_DET 148b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 149b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 150b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* MVS_TX_CFG */ 151b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TX_EN = (1U << 16), /* Enable TX */ 152b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TX_RING_SZ_MASK = 0xfff, /* TX ring size, bits 11:0 */ 153b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 154b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* MVS_RX_CFG */ 155b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik RX_EN = (1U << 16), /* Enable RX */ 156b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik RX_RING_SZ_MASK = 0xfff, /* RX ring size, bits 11:0 */ 157b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 158b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* MVS_INT_COAL */ 159b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik COAL_EN = (1U << 16), /* Enable int coalescing */ 160b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 161b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* MVS_INT_STAT, MVS_INT_MASK */ 162b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CINT_I2C = (1U << 31), /* I2C event */ 163b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CINT_SW0 = (1U << 30), /* software event 0 */ 164b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CINT_SW1 = (1U << 29), /* software event 1 */ 165b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CINT_PRD_BC = (1U << 28), /* PRD BC err for read cmd */ 166b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CINT_DMA_PCIE = (1U << 27), /* DMA to PCIE timeout */ 167b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CINT_MEM = (1U << 26), /* int mem parity err */ 168b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CINT_I2C_SLAVE = (1U << 25), /* slave I2C event */ 169b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CINT_SRS = (1U << 3), /* SRS event */ 170b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CINT_CI_STOP = (1U << 10), /* cmd issue stopped */ 171b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CINT_DONE = (1U << 0), /* cmd completion */ 172b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 173b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* shl for ports 1-3 */ 174b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CINT_PORT_STOPPED = (1U << 16), /* port0 stopped */ 175b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CINT_PORT = (1U << 8), /* port0 event */ 176b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 177b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* TX (delivery) ring bits */ 178b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TXQ_CMD_SHIFT = 29, 179b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TXQ_CMD_SSP = 1, /* SSP protocol */ 180b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TXQ_CMD_SMP = 2, /* SMP protocol */ 181b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TXQ_CMD_STP = 3, /* STP/SATA protocol */ 182b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TXQ_CMD_SSP_FREE_LIST = 4, /* add to SSP targ free list */ 183b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TXQ_CMD_SLOT_RESET = 7, /* reset command slot */ 184b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TXQ_MODE_I = (1U << 28), /* mode: 0=target,1=initiator */ 185b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TXQ_PRIO_HI = (1U << 27), /* priority: 0=normal, 1=high */ 186b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TXQ_SRS_SHIFT = 20, /* SATA register set */ 187b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TXQ_SRS_MASK = 0x7f, 188b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TXQ_PHY_SHIFT = 12, /* PHY bitmap */ 189b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TXQ_PHY_MASK = 0xff, 190b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik TXQ_SLOT_MASK = 0xfff, /* slot number */ 191b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 192b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* RX (completion) ring bits */ 193b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik RXQ_GOOD = (1U << 23), /* Response good */ 194b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik RXQ_SLOT_RESET = (1U << 21), /* Slot reset complete */ 195b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik RXQ_CMD_RX = (1U << 20), /* target cmd received */ 196b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik RXQ_ATTN = (1U << 19), /* attention */ 197b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik RXQ_RSP = (1U << 18), /* response frame xfer'd */ 198b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik RXQ_ERR = (1U << 17), /* err info rec xfer'd */ 199b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik RXQ_DONE = (1U << 16), /* cmd complete */ 200b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik RXQ_SLOT_MASK = 0xfff, /* slot number */ 201b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 202b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* mvs_cmd_hdr bits */ 203b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_PRD_LEN_SHIFT = 16, /* 16-bit PRD table len */ 204b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_SSP_FR_TYPE_SHIFT = 13, /* SSP frame type */ 205b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 206b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* SSP initiator only */ 207b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_SSP_FR_CMD = 0x0, /* COMMAND frame */ 208b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 209b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* SSP initiator or target */ 210b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_SSP_FR_TASK = 0x1, /* TASK frame */ 211b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 212b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* SSP target only */ 213b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_SSP_FR_XFER_RDY = 0x4, /* XFER_RDY frame */ 214b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_SSP_FR_RESP = 0x5, /* RESPONSE frame */ 215b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_SSP_FR_READ = 0x6, /* Read DATA frame(s) */ 216b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_SSP_FR_READ_RESP = 0x7, /* ditto, plus RESPONSE */ 217b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 218b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_PASSTHRU = (1U << 12), /* pass-through (SSP) */ 219b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_FBURST = (1U << 11), /* first burst (SSP) */ 220b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_CHK_LEN = (1U << 10), /* chk xfer len (SSP) */ 221b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_RETRY = (1U << 9), /* tport layer retry (SSP) */ 222b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_PROTECTION = (1U << 8), /* protection info rec (SSP) */ 223b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_RESET = (1U << 7), /* Reset (STP/SATA) */ 224b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_FPDMA = (1U << 6), /* First party DMA (STP/SATA) */ 225b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_ATAPI = (1U << 5), /* ATAPI (STP/SATA) */ 226b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_BIST = (1U << 4), /* BIST activate (STP/SATA) */ 227b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MCH_PMP_MASK = 0xf, /* PMP from cmd FIS (STP/SATA)*/ 228b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 229b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CCTL_RST = (1U << 5), /* port logic reset */ 230b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 231b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* 0(LSB first), 1(MSB first) */ 232b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CCTL_ENDIAN_DATA = (1U << 3), /* PRD data */ 233b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CCTL_ENDIAN_RSP = (1U << 2), /* response frame */ 234b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CCTL_ENDIAN_OPEN = (1U << 1), /* open address frame */ 235b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CCTL_ENDIAN_CMD = (1U << 0), /* command table */ 236b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 237b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* MVS_Px_SER_CTLSTAT (per-phy control) */ 238b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHY_SSP_RST = (1U << 3), /* reset SSP link layer */ 239b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHY_BCAST_CHG = (1U << 2), /* broadcast(change) notif */ 240b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHY_RST_HARD = (1U << 1), /* hard reset + phy reset */ 241b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHY_RST = (1U << 0), /* phy reset */ 242b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 243b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */ 244b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_UNASSOC_FIS = (1U << 19), /* unassociated FIS rx'd */ 245b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_AN = (1U << 18), /* SATA async notification */ 246b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_BIST_ACT = (1U << 17), /* BIST activate FIS */ 247b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_SIG_FIS = (1U << 16), /* signature FIS */ 248b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_POOF = (1U << 12), /* phy ready from 1 -> 0 */ 249b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_IU_BIG = (1U << 11), /* IU too long err */ 250b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_IU_SMALL = (1U << 10), /* IU too short err */ 251b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_UNK_TAG = (1U << 9), /* unknown tag */ 252b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_BROAD_CH = (1U << 8), /* broadcast(CHANGE) */ 253b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_COMWAKE = (1U << 7), /* COMWAKE rx'd */ 254b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_PORT_SEL = (1U << 6), /* port selector present */ 255b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_HARD_RST = (1U << 5), /* hard reset rx'd */ 256b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_ID_TMOUT = (1U << 4), /* identify timeout */ 257b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_ID_FAIL = (1U << 3), /* identify failed */ 258b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_ID_DONE = (1U << 2), /* identify done */ 259b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_HARD_RST_DONE = (1U << 1), /* hard reset done */ 260b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYEV_RDY_CH = (1U << 0), /* phy ready changed state */ 261b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 262b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* MVS_PCS */ 263b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PCS_SATA_RETRY = (1U << 8), /* retry ctl FIS on R_ERR */ 264b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PCS_RSP_RX_EN = (1U << 7), /* raw response rx */ 265b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PCS_SELF_CLEAR = (1U << 5), /* self-clearing int mode */ 266b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PCS_FIS_RX_EN = (1U << 4), /* FIS rx enable */ 267b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PCS_CMD_STOP_ERR = (1U << 3), /* cmd stop-on-err enable */ 268b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PCS_CMD_RST = (1U << 2), /* reset cmd issue */ 269b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PCS_CMD_EN = (1U << 0), /* enable cmd issue */ 270b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 271b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 272b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum mvs_info_flags { 273b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVF_MSI = (1U << 0), /* MSI is enabled */ 274b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik MVF_PHY_PWR_FIX = (1U << 1), /* bug workaround */ 275b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 276b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 277b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum sas_cmd_port_registers { 278b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_CMRST_OOB_DET = 0x100, /* COMRESET OOB detect register */ 279b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_CMWK_OOB_DET = 0x104, /* COMWAKE OOB detect register */ 280b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_CMSAS_OOB_DET = 0x108, /* COMSAS OOB detect register */ 281b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_BRST_OOB_DET = 0x10c, /* burst OOB detect register */ 282b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_OOB_SPACE = 0x110, /* OOB space control register */ 283b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_OOB_BURST = 0x114, /* OOB burst control register */ 284b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PHY_TIMER = 0x118, /* PHY timer control register */ 285b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PHY_CONFIG0 = 0x11c, /* PHY config register 0 */ 286b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PHY_CONFIG1 = 0x120, /* PHY config register 1 */ 287b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_SAS_CTL0 = 0x124, /* SAS control register 0 */ 288b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_SAS_CTL1 = 0x128, /* SAS control register 1 */ 289b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_SAS_CTL2 = 0x12c, /* SAS control register 2 */ 290b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_SAS_CTL3 = 0x130, /* SAS control register 3 */ 291b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_ID_TEST = 0x134, /* ID test register */ 292b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PL_TIMER = 0x138, /* PL timer register */ 293b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_WD_TIMER = 0x13c, /* WD timer register */ 294b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PORT_SEL_COUNT = 0x140, /* port selector count register */ 295b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_APP_MEM_CTL = 0x144, /* Application Memory Control */ 296b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_XOR_MEM_CTL = 0x148, /* XOR Block Memory Control */ 297b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_DMA_MEM_CTL = 0x14c, /* DMA Block Memory Control */ 298b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PORT_MEM_CTL0 = 0x150, /* Port Memory Control 0 */ 299b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PORT_MEM_CTL1 = 0x154, /* Port Memory Control 1 */ 300b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_SATA_PORT_MEM_CTL0 = 0x158, /* SATA Port Memory Control 0 */ 301b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_SATA_PORT_MEM_CTL1 = 0x15c, /* SATA Port Memory Control 1 */ 302b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_XOR_MEM_BIST_CTL = 0x160, /* XOR Memory BIST Control */ 303b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_XOR_MEM_BIST_STAT = 0x164, /* XOR Memroy BIST Status */ 304b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_DMA_MEM_BIST_CTL = 0x168, /* DMA Memory BIST Control */ 305b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_DMA_MEM_BIST_STAT = 0x16c, /* DMA Memory BIST Status */ 306b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PORT_MEM_BIST_CTL = 0x170, /* Port Memory BIST Control */ 307b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PORT_MEM_BIST_STAT0 = 0x174, /* Port Memory BIST Status 0 */ 308b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PORT_MEM_BIST_STAT1 = 0x178, /* Port Memory BIST Status 1 */ 309b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_STP_MEM_BIST_CTL = 0x17c, /* STP Memory BIST Control */ 310b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_STP_MEM_BIST_STAT0 = 0x180, /* STP Memory BIST Status 0 */ 311b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_STP_MEM_BIST_STAT1 = 0x184, /* STP Memory BIST Status 1 */ 312b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_RESET_COUNT = 0x188, /* Reset Count */ 313b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_MONTR_DATA_SEL = 0x18C, /* Monitor Data/Select */ 314b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PLL_PHY_CONFIG = 0x190, /* PLL/PHY Configuration */ 315b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PHY_CTL = 0x194, /* PHY Control and Status */ 316b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PHY_TEST_COUNT0 = 0x198, /* Phy Test Count 0 */ 317b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PHY_TEST_COUNT1 = 0x19C, /* Phy Test Count 1 */ 318b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PHY_TEST_COUNT2 = 0x1A0, /* Phy Test Count 2 */ 319b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_APP_ERR_CONFIG = 0x1A4, /* Application Error Configuration */ 320b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PND_FIFO_CTL0 = 0x1A8, /* Pending FIFO Control 0 */ 321b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_HOST_CTL = 0x1AC, /* Host Control Status */ 322b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_HOST_WR_DATA = 0x1B0, /* Host Write Data */ 323b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_HOST_RD_DATA = 0x1B4, /* Host Read Data */ 324b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PHY_MODE_21 = 0x1B8, /* Phy Mode 21 */ 325b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_SL_MODE0 = 0x1BC, /* SL Mode 0 */ 326b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_SL_MODE1 = 0x1C0, /* SL Mode 1 */ 327b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik CMD_PND_FIFO_CTL1 = 0x1C4, /* Pending FIFO Control 1 */ 328b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 329b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 330b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* SAS/SATA configuration port registers, aka phy registers */ 331b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum sas_sata_config_port_regs { 332b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYR_IDENTIFY = 0x0, /* info for IDENTIFY frame */ 333b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYR_ADDR_LO = 0x4, /* my SAS address (low) */ 334b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYR_ADDR_HI = 0x8, /* my SAS address (high) */ 335b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYR_ATT_DEV_INFO = 0xC, /* attached device info */ 336b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYR_ATT_ADDR_LO = 0x10, /* attached dev SAS addr (low) */ 337b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYR_ATT_ADDR_HI = 0x14, /* attached dev SAS addr (high) */ 338b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYR_SATA_CTL = 0x18, /* SATA control */ 339b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYR_PHY_STAT = 0x1C, /* PHY status */ 340b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYR_WIDE_PORT = 0x38, /* wide port participating */ 341b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYR_CURRENT0 = 0x80, /* current connection info 0 */ 342b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYR_CURRENT1 = 0x84, /* current connection info 1 */ 343b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PHYR_CURRENT2 = 0x88, /* current connection info 2 */ 344b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 345b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 346b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum pci_cfg_registers { 347b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PCR_PHY_CTL = 0x40, 348b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PCR_PHY_CTL2 = 0x90, 349b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 350b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 351b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum pci_cfg_register_bits { 352b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PCTL_PWR_ON = (0xFU << 24), 353b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PCTL_OFF = (0xFU << 12), 354b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 355b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 356b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum nvram_layout_offsets { 357b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik NVR_SIG = 0x00, /* 0xAA, 0x55 */ 358b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik NVR_SAS_ADDR = 0x02, /* 8-byte SAS address */ 359b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 360b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 361b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum chip_flavors { 362b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik chip_6320, 363b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik chip_6440, 364b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik chip_6480, 365b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 366b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 367b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_chip_info { 368b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned int n_phy; 369b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned int srs_sz; 370b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned int slot_width; 371b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 372b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 373b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_err_info { 374b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le32 flags; 375b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le32 flags2; 376b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 377b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 378b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_prd { 379b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le64 addr; /* 64-bit buffer address */ 380b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le32 reserved; 381b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le32 len; /* 16-bit length */ 382b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 383b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 384b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_cmd_hdr { 385b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le32 flags; /* PRD tbl len; SAS, SATA ctl */ 386b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le32 lens; /* cmd, max resp frame len */ 387b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le32 tags; /* targ port xfer tag; tag */ 388b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le32 data_len; /* data xfer len */ 389b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le64 cmd_tbl; /* command table address */ 390b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le64 open_frame; /* open addr frame address */ 391b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le64 status_buf; /* status buffer address */ 392b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le64 prd_tbl; /* PRD tbl address */ 393b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le32 reserved[4]; 394b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 395b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 396b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_slot_info { 397b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct sas_task *task; 398b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned int n_elem; 399b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 400b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* DMA buffer for storing cmd tbl, open addr frame, status buffer, 401b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * and PRD table 402b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 403b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void *buf; 404b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dma_addr_t buf_dma; 405b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 406b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void *response; 407b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 408b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 409b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_port { 410b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct asd_sas_port sas_port; 411b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 412b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 413b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_phy { 414b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_port *port; 415b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct asd_sas_phy sas_phy; 416b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 417b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u8 frame_rcvd[24 + 1024]; 418b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 419b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 420b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_info { 421b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned long flags; 422b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 423b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik spinlock_t lock; /* host-wide lock */ 424b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct pci_dev *pdev; /* our device */ 425b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void __iomem *regs; /* enhanced mode registers */ 426b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void __iomem *peri_regs; /* peripheral registers */ 427b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 428b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u8 sas_addr[SAS_ADDR_SIZE]; 429b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct sas_ha_struct sas; /* SCSI/SAS glue */ 430b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct Scsi_Host *shost; 431b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 432b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le32 *tx; /* TX (delivery) DMA ring */ 433b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dma_addr_t tx_dma; 434b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 tx_prod; /* cached next-producer idx */ 435b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 436b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le32 *rx; /* RX (completion) DMA ring */ 437b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dma_addr_t rx_dma; 438b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 rx_cons; /* RX consumer idx */ 439b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 440b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik __le32 *rx_fis; /* RX'd FIS area */ 441b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dma_addr_t rx_fis_dma; 442b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 443b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_cmd_hdr *slot; /* DMA command header slots */ 444b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dma_addr_t slot_dma; 445b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 446b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik const struct mvs_chip_info *chip; 447b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 448b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* further per-slot information */ 449b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_slot_info slot_info[MVS_SLOTS]; 450b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned long tags[(MVS_SLOTS / sizeof(unsigned long)) + 1]; 451b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 452b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_phy phy[MVS_MAX_PHYS]; 453b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_port port[MVS_MAX_PHYS]; 454b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 455b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 456b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct scsi_transport_template *mvs_stt; 457b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 458b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic const struct mvs_chip_info mvs_chips[] = { 459b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik [chip_6320] = { 2, 16, 9 }, 460b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik [chip_6440] = { 4, 16, 9 }, 461b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik [chip_6480] = { 8, 32, 10 }, 462b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 463b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 464b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct scsi_host_template mvs_sht = { 465b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .module = THIS_MODULE, 466b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .name = DRV_NAME, 467b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .queuecommand = sas_queuecommand, 468b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .target_alloc = sas_target_alloc, 469b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .slave_configure = sas_slave_configure, 470b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .slave_destroy = sas_slave_destroy, 471b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .change_queue_depth = sas_change_queue_depth, 472b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .change_queue_type = sas_change_queue_type, 473b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .bios_param = sas_bios_param, 474b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .can_queue = 1, 475b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .cmd_per_lun = 1, 476b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .this_id = -1, 477b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .sg_tablesize = SG_ALL, 478b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .max_sectors = SCSI_DEFAULT_MAX_SECTORS, 479b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .use_clustering = ENABLE_CLUSTERING, 480b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .eh_device_reset_handler= sas_eh_device_reset_handler, 481b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .eh_bus_reset_handler = sas_eh_bus_reset_handler, 482b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .slave_alloc = sas_slave_alloc, 483b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .target_destroy = sas_target_destroy, 484b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .ioctl = sas_ioctl, 485b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 486b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 487b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_int_rx(struct mvs_info *mvi, bool self_clear); 488b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 489b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* move to PCI layer or libata core? */ 490b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int pci_go_64(struct pci_dev *pdev) 491b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 492b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik int rc; 493b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 494b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { 495b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); 496b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) { 497b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 498b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) { 499b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 500b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik "64-bit DMA enable failed\n"); 501b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 502b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 503b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 504b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } else { 505b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 506b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) { 507b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 508b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik "32-bit DMA enable failed\n"); 509b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 510b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 511b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 512b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) { 513b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 514b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik "32-bit consistent DMA enable failed\n"); 515b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 516b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 517b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 518b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 519b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 520b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 521b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 522b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_tag_clear(struct mvs_info *mvi, unsigned int tag) 523b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 524b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->tags[tag / sizeof(unsigned long)] &= 525b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik ~(1UL << (tag % sizeof(unsigned long))); 526b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 527b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 528b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_tag_set(struct mvs_info *mvi, unsigned int tag) 529b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 530b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->tags[tag / sizeof(unsigned long)] |= 531b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik (1UL << (tag % sizeof(unsigned long))); 532b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 533b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 534b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic bool mvs_tag_test(struct mvs_info *mvi, unsigned int tag) 535b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 536b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return mvi->tags[tag / sizeof(unsigned long)] & 537b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik (1UL << (tag % sizeof(unsigned long))); 538b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 539b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 540b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_tag_alloc(struct mvs_info *mvi, unsigned int *tag_out) 541b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 542b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned int i; 543b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 544b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik for (i = 0; i < MVS_SLOTS; i++) 545b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!mvs_tag_test(mvi, i)) { 546b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_tag_set(mvi, i); 547b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik *tag_out = i; 548b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 549b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 550b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 551b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return -EBUSY; 552b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 553b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 554b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_eep_read(void __iomem *regs, unsigned int addr, u32 *data) 555b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 556b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik int timeout = 1000; 557b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 558b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (addr & ~SPI_ADDR_MASK) 559b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return -EINVAL; 560b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 561b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik writel(addr, regs + SPI_CMD); 562b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik writel(TWSI_RD, regs + SPI_CTL); 563b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 564b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik while (timeout-- > 0) { 565b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (readl(regs + SPI_CTL) & TWSI_RDY) { 566b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik *data = readl(regs + SPI_DATA); 567b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 568b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 569b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 570b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik udelay(10); 571b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 572b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 573b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return -EBUSY; 574b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 575b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 576b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_eep_read_buf(void __iomem *regs, unsigned int addr, 577b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void *buf, unsigned int buflen) 578b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 579b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned int addr_end, tmp_addr, i, j; 580b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 tmp = 0; 581b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik int rc; 582b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u8 *tmp8, *buf8 = buf; 583b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 584b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik addr_end = addr + buflen; 585b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp_addr = ALIGN(addr, 4); 586b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (addr > 0xff) 587b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return -EINVAL; 588b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 589b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik j = addr & 0x3; 590b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (j) { 591b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = mvs_eep_read(regs, tmp_addr, &tmp); 592b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) 593b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 594b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 595b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp8 = (u8 *) &tmp; 596b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik for (i = j; i < 4; i++) 597b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik *buf8++ = tmp8[i]; 598b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 599b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp_addr += 4; 600b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 601b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 602b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik for (j = ALIGN(addr_end, 4); tmp_addr < j; tmp_addr += 4) { 603b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = mvs_eep_read(regs, tmp_addr, &tmp); 604b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) 605b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 606b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 607b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memcpy(buf8, &tmp, 4); 608b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf8 += 4; 609b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 610b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 611b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (tmp_addr < addr_end) { 612b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = mvs_eep_read(regs, tmp_addr, &tmp); 613b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) 614b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 615b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 616b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp8 = (u8 *) &tmp; 617b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik j = addr_end - tmp_addr; 618b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik for (i = 0; i < j; i++) 619b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik *buf8++ = tmp8[i]; 620b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 621b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp_addr += 4; 622b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 623b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 624b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 625b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 626b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 627b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_nvram_read(struct mvs_info *mvi, unsigned int addr, 628b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void *buf, unsigned int buflen) 629b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 630b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void __iomem *regs = mvi->regs; 631b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik int rc, i; 632b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned int sum; 633b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u8 hdr[2], *tmp; 634b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik const char *msg; 635b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 636b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = mvs_eep_read_buf(regs, addr, &hdr, 2); 637b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) { 638b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik msg = "nvram hdr read failed"; 639b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 640b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 641b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = mvs_eep_read_buf(regs, addr + 2, buf, buflen); 642b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) { 643b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik msg = "nvram read failed"; 644b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 645b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 646b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 647b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (hdr[0] != 0x5A) { /* entry id */ 648b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik msg = "invalid nvram entry id"; 649b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = -ENOENT; 650b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 651b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 652b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 653b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp = buf; 654b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sum = ((unsigned int)hdr[0]) + ((unsigned int)hdr[1]); 655b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik for (i = 0; i < buflen; i++) 656b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sum += ((unsigned int)tmp[i]); 657b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 658b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (sum) { 659b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik msg = "nvram checksum failure"; 660b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = -EILSEQ; 661b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 662b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 663b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 664b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 665b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 666b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out: 667b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg); 668b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 669b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 670b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 671b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_int_port(struct mvs_info *mvi, int port_no, u32 events) 672b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 673b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* FIXME */ 674b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 675b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 676b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_int_sata(struct mvs_info *mvi) 677b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 678b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* FIXME */ 679b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 680b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 681b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_slot_free(struct mvs_info *mvi, struct sas_task *task, 682b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_slot_info *slot, unsigned int slot_idx) 683b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 684b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (slot->n_elem) 685b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_unmap_sg(mvi->pdev, task->scatter, 686b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik slot->n_elem, task->data_dir); 687b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 688b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik switch (task->task_proto) { 689b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case SAS_PROTOCOL_SMP: 690b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_unmap_sg(mvi->pdev, &task->smp_task.smp_resp, 1, 691b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PCI_DMA_FROMDEVICE); 692b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_unmap_sg(mvi->pdev, &task->smp_task.smp_req, 1, 693b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PCI_DMA_TODEVICE); 694b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 695b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 696b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case SAS_PROTOCOL_SATA: 697b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case SAS_PROTOCOL_STP: 698b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case SAS_PROTOCOL_SSP: 699b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik default: 700b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* do nothing */ 701b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 702b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 703b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 704b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_tag_clear(mvi, slot_idx); 705b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 706b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 707b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_slot_err(struct mvs_info *mvi, struct sas_task *task, 708b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned int slot_idx) 709b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 710b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* FIXME */ 711b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 712b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 713b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc) 714b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 715b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned int slot_idx = rx_desc & RXQ_SLOT_MASK; 716b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; 717b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct sas_task *task = slot->task; 718b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct task_status_struct *tstat = &task->task_status; 719b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik bool aborted; 720b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 721b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik spin_lock(&task->task_state_lock); 722b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED; 723b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!aborted) { 724b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik task->task_state_flags &= 725b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); 726b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik task->task_state_flags |= SAS_TASK_STATE_DONE; 727b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 728b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik spin_unlock(&task->task_state_lock); 729b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 730b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (aborted) 731b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return; 732b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 733b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memset(tstat, 0, sizeof(*tstat)); 734b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tstat->resp = SAS_TASK_COMPLETE; 735b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 736b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* error info record present */ 737b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rx_desc & RXQ_ERR) { 738b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tstat->stat = SAM_CHECK_COND; 739b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_slot_err(mvi, task, slot_idx); 740b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto out; 741b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 742b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 743b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik switch (task->task_proto) { 744b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case SAS_PROTOCOL_SSP: 745b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* hw says status == 0, datapres == 0 */ 746b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rx_desc & RXQ_GOOD) 747b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tstat->stat = SAM_GOOD; 748b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 749b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* response frame present */ 750b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik else if (rx_desc & RXQ_RSP) { 751b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct ssp_response_iu *iu = 752b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik slot->response + sizeof(struct mvs_err_info); 753b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_ssp_task_response(&mvi->pdev->dev, task, iu); 754b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 755b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 756b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* should never happen? */ 757b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik else 758b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tstat->stat = SAM_CHECK_COND; 759b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 760b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 761b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case SAS_PROTOCOL_SMP: 762b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tstat->stat = SAM_GOOD; 763b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 764b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 765b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case SAS_PROTOCOL_SATA: 766b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case SAS_PROTOCOL_STP: 767b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if ((rx_desc & (RXQ_DONE | RXQ_ERR | RXQ_ATTN)) == RXQ_DONE) 768b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tstat->stat = SAM_GOOD; 769b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik else 770b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tstat->stat = SAM_CHECK_COND; 771b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* FIXME: read taskfile data from SATA register set 772b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * associated with SATA target 773b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 774b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 775b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 776b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik default: 777b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tstat->stat = SAM_CHECK_COND; 778b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 779b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 780b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 781b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikout: 782b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_slot_free(mvi, task, slot, slot_idx); 783b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik task->task_done(task); 784b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 785b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 786b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_int_full(struct mvs_info *mvi) 787b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 788b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void __iomem *regs = mvi->regs; 789b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 tmp, stat; 790b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik int i; 791b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 792b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik stat = mr32(INT_STAT); 793b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 794b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik for (i = 0; i < MVS_MAX_PORTS; i++) { 795b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED); 796b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (tmp) 797b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_int_port(mvi, i, tmp); 798b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 799b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 800b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (stat & CINT_SRS) 801b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_int_sata(mvi); 802b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 803b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (stat & (CINT_CI_STOP | CINT_DONE)) 804b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_int_rx(mvi, false); 805b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 806b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(INT_STAT, stat); 807b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 808b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 809b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_int_rx(struct mvs_info *mvi, bool self_clear) 810b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 811b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 rx_prod_idx, rx_desc; 812b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik bool attn = false; 813b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 814b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* the first dword in the RX ring is special: it contains 815b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * a mirror of the hardware's RX producer index, so that 816b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * we don't have to stall the CPU reading that register. 817b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * The actual RX ring is offset by one dword, due to this. 818b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 819b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rx_prod_idx = le32_to_cpu(mvi->rx[0]) & 0xfff; 820b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rx_prod_idx == 0xfff) { /* h/w hasn't touched RX ring yet */ 821b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->rx_cons = 0xfff; 822b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return; 823b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 824b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (mvi->rx_cons == 0xfff) 825b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->rx_cons = MVS_RX_RING_SZ - 1; 826b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 827b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik while (mvi->rx_cons != rx_prod_idx) { 828b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* increment our internal RX consumer pointer */ 829b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->rx_cons = (mvi->rx_cons + 1) & (MVS_RX_RING_SZ - 1); 830b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 831b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* Read RX descriptor at offset+1, due to above */ 832b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rx_desc = le32_to_cpu(mvi->rx[mvi->rx_cons + 1]); 833b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 834b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rx_desc & RXQ_DONE) 835b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* we had a completion, error or no */ 836b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_slot_complete(mvi, rx_desc); 837b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 838b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rx_desc & RXQ_ATTN) 839b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik attn = true; 840b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 841b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 842b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (attn && self_clear) 843b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_int_full(mvi); 844b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 845b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 846b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 847b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic irqreturn_t mvs_interrupt(int irq, void *opaque) 848b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 849b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_info *mvi = opaque; 850b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void __iomem *regs = mvi->regs; 851b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 stat; 852b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 853b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik stat = mr32(GBL_INT_STAT); 854b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (stat == 0 || stat == 0xffffffff) 855b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return IRQ_NONE; 856b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 857b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik spin_lock(&mvi->lock); 858b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 859b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_int_full(mvi); 860b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 861b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik spin_unlock(&mvi->lock); 862b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 863b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return IRQ_HANDLED; 864b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 865b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 866b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic irqreturn_t mvs_msi_interrupt(int irq, void *opaque) 867b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 868b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_info *mvi = opaque; 869b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 870b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik spin_lock(&mvi->lock); 871b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 872b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_int_rx(mvi, true); 873b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 874b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik spin_unlock(&mvi->lock); 875b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 876b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return IRQ_HANDLED; 877b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 878b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 879b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_task_exec_info { 880b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct sas_task *task; 881b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_cmd_hdr *hdr; 882b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned int tag; 883b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik int n_elem; 884b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 885b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 886b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_task_prep_smp(struct mvs_info *mvi, struct mvs_task_exec_info *tei) 887b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 888b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik int elem, rc; 889b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_cmd_hdr *hdr = tei->hdr; 890b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct scatterlist *sg_req, *sg_resp; 891b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned int req_len, resp_len, tag = tei->tag; 892b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 893b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* 894b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * DMA-map SMP request, response buffers 895b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 896b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 897b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sg_req = &tei->task->smp_task.smp_req; 898b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik elem = pci_map_sg(mvi->pdev, sg_req, 1, PCI_DMA_TODEVICE); 899b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!elem) 900b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return -ENOMEM; 901b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik req_len = sg_dma_len(sg_req); 902b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 903b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sg_resp = &tei->task->smp_task.smp_resp; 904b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik elem = pci_map_sg(mvi->pdev, sg_resp, 1, PCI_DMA_FROMDEVICE); 905b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!elem) { 906b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = -ENOMEM; 907b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 908b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 909b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik resp_len = sg_dma_len(sg_resp); 910b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 911b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* must be in dwords */ 912b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if ((req_len & 0x3) || (resp_len & 0x3)) { 913b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = -EINVAL; 914b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out_2; 915b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 916b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 917b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* 918b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * Fill in TX ring and command slot header 919b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 920b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 921b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->tx[tag] = cpu_to_le32( 922b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik (TXQ_CMD_SMP << TXQ_CMD_SHIFT) | TXQ_MODE_I | tag); 923b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 924b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->flags = 0; 925b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4)); 926b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->tags = cpu_to_le32(tag); 927b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->data_len = 0; 928b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req)); 929b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->open_frame = 0; 930b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->status_buf = cpu_to_le64(sg_dma_address(sg_resp)); 931b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->prd_tbl = 0; 932b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 933b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 934b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 935b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_2: 936b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_resp, 1, 937b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PCI_DMA_FROMDEVICE); 938b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out: 939b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_req, 1, 940b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik PCI_DMA_TODEVICE); 941b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 942b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 943b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 944b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_task_prep_ata(struct mvs_info *mvi, 945b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_task_exec_info *tei) 946b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 947b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct sas_task *task = tei->task; 948b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct domain_device *dev = task->dev; 949b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_cmd_hdr *hdr = tei->hdr; 950b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct asd_sas_port *sas_port = dev->port; 951b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned int tag = tei->tag; 952b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_slot_info *slot = &mvi->slot_info[tag]; 953b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT); 954b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct scatterlist *sg; 955b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_prd *buf_prd; 956b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void *buf_tmp; 957b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u8 *buf_cmd, *buf_oaf; 958b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dma_addr_t buf_tmp_dma; 959b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned int i, req_len, resp_len; 960b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 961b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* FIXME: fill in SATA register set */ 962b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->tx[tag] = cpu_to_le32(TXQ_MODE_I | tag | 963b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik (TXQ_CMD_STP << TXQ_CMD_SHIFT) | 964b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik (sas_port->phy_mask << TXQ_PHY_SHIFT)); 965b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 966b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (task->ata_task.use_ncq) 967b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik flags |= MCH_FPDMA; 968b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) 969b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik flags |= MCH_ATAPI; 970b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* FIXME: fill in port multiplier number */ 971b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 972b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->flags = cpu_to_le32(flags); 973b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->tags = cpu_to_le32(tag); 974b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->data_len = cpu_to_le32(task->total_xfer_len); 975b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 976b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* 977b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs 978b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 979b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memset(slot->buf, 0, MVS_SLOT_BUF_SZ); 980b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 981b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ***************/ 982b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_cmd = 983b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp = slot->buf; 984b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma = slot->buf_dma; 985b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 986b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); 987b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 988b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += MVS_ATA_CMD_SZ; 989b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += MVS_ATA_CMD_SZ; 990b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 991b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* region 2: open address frame area (MVS_OAF_SZ bytes) **********/ 992b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* used for STP. unused for SATA? */ 993b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_oaf = buf_tmp; 994b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->open_frame = cpu_to_le64(buf_tmp_dma); 995b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 996b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += MVS_OAF_SZ; 997b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += MVS_OAF_SZ; 998b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 999b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* region 3: PRD table ***********************************************/ 1000b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd = buf_tmp; 1001b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); 1002b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1003b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik i = sizeof(struct mvs_prd) * tei->n_elem; 1004b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += i; 1005b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += i; 1006b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1007b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* region 4: status buffer (larger the PRD, smaller this buf) ********/ 1008b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* FIXME: probably unused, for SATA. kept here just in case 1009b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * we get a STP/SATA error information record 1010b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 1011b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik slot->response = buf_tmp; 1012b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->status_buf = cpu_to_le64(buf_tmp_dma); 1013b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1014b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik req_len = sizeof(struct ssp_frame_hdr) + 28; 1015b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ - 1016b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sizeof(struct mvs_err_info) - i; 1017b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1018b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* request, response lengths */ 1019b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4)); 1020b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1021b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* fill in command FIS and ATAPI CDB */ 1022b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memcpy(buf_cmd, &task->ata_task.fis, 1023b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sizeof(struct host_to_dev_fis)); 1024b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memcpy(buf_cmd + 0x40, task->ata_task.atapi_packet, 16); 1025b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1026b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* fill in PRD (scatter/gather) table, if any */ 1027b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sg = task->scatter; 1028b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik for (i = 0; i < tei->n_elem; i++) { 1029b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); 1030b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd->len = cpu_to_le32(sg_dma_len(sg)); 1031b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1032b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sg++; 1033b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd++; 1034b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1035b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1036b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 1037b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1038b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1039b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_task_prep_ssp(struct mvs_info *mvi, 1040b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_task_exec_info *tei) 1041b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1042b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct sas_task *task = tei->task; 1043b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct asd_sas_port *sas_port = task->dev->port; 1044b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_cmd_hdr *hdr = tei->hdr; 1045b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_slot_info *slot; 1046b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct scatterlist *sg; 1047b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned int resp_len, req_len, i, tag = tei->tag; 1048b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_prd *buf_prd; 1049b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct ssp_frame_hdr *ssp_hdr; 1050b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void *buf_tmp; 1051b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u8 *buf_cmd, *buf_oaf, fburst = 0; 1052b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dma_addr_t buf_tmp_dma; 1053b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 flags; 1054b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1055b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik slot = &mvi->slot_info[tag]; 1056b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1057b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->tx[tag] = cpu_to_le32(TXQ_MODE_I | tag | 1058b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik (TXQ_CMD_SSP << TXQ_CMD_SHIFT) | 1059b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik (sas_port->phy_mask << TXQ_PHY_SHIFT)); 1060b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1061b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik flags = MCH_RETRY; 1062b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (task->ssp_task.enable_first_burst) { 1063b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik flags |= MCH_FBURST; 1064b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik fburst = (1 << 7); 1065b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1066b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->flags = cpu_to_le32(flags | 1067b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik (tei->n_elem << MCH_PRD_LEN_SHIFT) | 1068b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT)); 1069b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1070b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->tags = cpu_to_le32(tag); 1071b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->data_len = cpu_to_le32(task->total_xfer_len); 1072b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1073b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* 1074b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs 1075b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 1076b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memset(slot->buf, 0, MVS_SLOT_BUF_SZ); 1077b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1078b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ***************/ 1079b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_cmd = 1080b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp = slot->buf; 1081b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma = slot->buf_dma; 1082b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1083b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); 1084b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1085b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += MVS_SSP_CMD_SZ; 1086b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += MVS_SSP_CMD_SZ; 1087b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1088b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* region 2: open address frame area (MVS_OAF_SZ bytes) **********/ 1089b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_oaf = buf_tmp; 1090b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->open_frame = cpu_to_le64(buf_tmp_dma); 1091b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1092b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += MVS_OAF_SZ; 1093b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += MVS_OAF_SZ; 1094b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1095b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* region 3: PRD table ***********************************************/ 1096b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd = buf_tmp; 1097b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); 1098b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1099b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik i = sizeof(struct mvs_prd) * tei->n_elem; 1100b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += i; 1101b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += i; 1102b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1103b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* region 4: status buffer (larger the PRD, smaller this buf) ********/ 1104b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik slot->response = buf_tmp; 1105b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->status_buf = cpu_to_le64(buf_tmp_dma); 1106b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1107b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik req_len = sizeof(struct ssp_frame_hdr) + 28; 1108b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ - 1109b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sizeof(struct mvs_err_info) - i; 1110b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1111b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* request, response lengths */ 1112b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4)); 1113b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1114b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* generate open address frame hdr (first 12 bytes) */ 1115b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_oaf[0] = (1 << 7) | (1 << 4) | 0x1; /* initiator, SSP, ftype 1h */ 1116b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_oaf[1] = task->dev->linkrate & 0xf; 1117b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_oaf[2] = tag >> 8; 1118b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_oaf[3] = tag; 1119b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE); 1120b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1121b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* fill in SSP frame header */ 1122b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik ssp_hdr = (struct ssp_frame_hdr *) buf_cmd; 1123b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik ssp_hdr->frame_type = SSP_COMMAND; 1124b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memcpy(ssp_hdr->hashed_dest_addr, task->dev->hashed_sas_addr, 1125b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik HASHED_SAS_ADDR_SIZE); 1126b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memcpy(ssp_hdr->hashed_src_addr, 1127b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik task->dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); 1128b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik ssp_hdr->tag = cpu_to_be16(tag); 1129b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1130b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* fill in command frame IU */ 1131b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_cmd += sizeof(*ssp_hdr); 1132b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memcpy(buf_cmd, &task->ssp_task.LUN, 8); 1133b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_cmd[9] = fburst | 1134b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik task->ssp_task.task_attr | 1135b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik (task->ssp_task.task_prio << 3); 1136b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16); 1137b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1138b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* fill in PRD (scatter/gather) table, if any */ 1139b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sg = task->scatter; 1140b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik for (i = 0; i < tei->n_elem; i++) { 1141b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); 1142b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd->len = cpu_to_le32(sg_dma_len(sg)); 1143b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1144b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sg++; 1145b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd++; 1146b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1147b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1148b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 1149b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1150b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1151b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags) 1152b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1153b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_info *mvi = task->dev->port->ha->lldd_ha; 1154b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned int tag = 0xdeadbeef, rc, n_elem = 0; 1155b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void __iomem *regs = mvi->regs; 1156b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned long flags; 1157b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_task_exec_info tei; 1158b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1159b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* FIXME: STP/SATA support not complete yet */ 1160b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (task->task_proto == SAS_PROTOCOL_SATA || task->task_proto == SAS_PROTOCOL_STP) 1161b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return -SAS_DEV_NO_RESPONSE; 1162b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1163b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (task->num_scatter) { 1164b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik n_elem = pci_map_sg(mvi->pdev, task->scatter, 1165b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik task->num_scatter, task->data_dir); 1166b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!n_elem) 1167b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return -ENOMEM; 1168b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1169b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1170b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik spin_lock_irqsave(&mvi->lock, flags); 1171b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1172b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = mvs_tag_alloc(mvi, &tag); 1173b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) 1174b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 1175b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1176b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->slot_info[tag].task = task; 1177b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->slot_info[tag].n_elem = n_elem; 1178b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tei.task = task; 1179b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tei.hdr = &mvi->slot[tag]; 1180b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tei.tag = tag; 1181b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tei.n_elem = n_elem; 1182b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1183b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik switch (task->task_proto) { 1184b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case SAS_PROTOCOL_SMP: 1185b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = mvs_task_prep_smp(mvi, &tei); 1186b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 1187b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case SAS_PROTOCOL_SSP: 1188b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = mvs_task_prep_ssp(mvi, &tei); 1189b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 1190b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case SAS_PROTOCOL_SATA: 1191b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case SAS_PROTOCOL_STP: 1192b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = mvs_task_prep_ata(mvi, &tei); 1193b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 1194b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik default: 1195b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = -EINVAL; 1196b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 1197b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1198b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1199b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) 1200b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out_tag; 1201b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1202b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* TODO: select normal or high priority */ 1203b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1204b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(RX_PROD_IDX, mvi->tx_prod); 1205b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1206b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_TX_RING_SZ - 1); 1207b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1208b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik spin_lock(&task->task_state_lock); 1209b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik task->task_state_flags |= SAS_TASK_AT_INITIATOR; 1210b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik spin_unlock(&task->task_state_lock); 1211b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1212b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik spin_unlock_irqrestore(&mvi->lock, flags); 1213b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 1214b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1215b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_tag: 1216b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_tag_clear(mvi, tag); 1217b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out: 1218b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (n_elem) 1219b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_unmap_sg(mvi->pdev, task->scatter, n_elem, task->data_dir); 1220b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik spin_unlock_irqrestore(&mvi->lock, flags); 1221b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 1222b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1223b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1224b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_free(struct mvs_info *mvi) 1225b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1226b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik int i; 1227b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1228b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!mvi) 1229b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return; 1230b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1231b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik for (i = 0; i < MVS_SLOTS; i++) { 1232b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_slot_info *slot = &mvi->slot_info[i]; 1233b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1234b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (slot->buf) 1235b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dma_free_coherent(&mvi->pdev->dev, MVS_SLOT_BUF_SZ, 1236b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik slot->buf, slot->buf_dma); 1237b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1238b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1239b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (mvi->tx) 1240b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dma_free_coherent(&mvi->pdev->dev, 1241b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sizeof(*mvi->tx) * MVS_TX_RING_SZ, 1242b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->tx, mvi->tx_dma); 1243b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (mvi->rx_fis) 1244b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dma_free_coherent(&mvi->pdev->dev, MVS_RX_FISL_SZ, 1245b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->rx_fis, mvi->rx_fis_dma); 1246b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (mvi->rx) 1247b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dma_free_coherent(&mvi->pdev->dev, 1248b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sizeof(*mvi->rx) * MVS_RX_RING_SZ, 1249b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->rx, mvi->rx_dma); 1250b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (mvi->slot) 1251b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dma_free_coherent(&mvi->pdev->dev, 1252b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sizeof(*mvi->slot) * MVS_RX_RING_SZ, 1253b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->slot, mvi->slot_dma); 1254b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (mvi->peri_regs) 1255b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik iounmap(mvi->peri_regs); 1256b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (mvi->regs) 1257b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik iounmap(mvi->regs); 1258b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (mvi->shost) 1259b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik scsi_host_put(mvi->shost); 1260b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik kfree(mvi->sas.sas_port); 1261b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik kfree(mvi->sas.sas_phy); 1262b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik kfree(mvi); 1263b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1264b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1265b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* FIXME: locking? */ 1266b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, 1267b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void *funcdata) 1268b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1269b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_info *mvi = sas_phy->ha->lldd_ha; 1270b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void __iomem *reg; 1271b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik int rc = 0, phy_id = sas_phy->id; 1272b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 tmp; 1273b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1274b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik reg = mvi->regs + MVS_P0_SER_CTLSTAT + (phy_id * 4); 1275b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1276b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik switch (func) { 1277b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case PHY_FUNC_SET_LINK_RATE: { 1278b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct sas_phy_linkrates *rates = funcdata; 1279b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 lrmin = 0, lrmax = 0; 1280b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1281b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik lrmin = (rates->minimum_linkrate << 8); 1282b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik lrmax = (rates->maximum_linkrate << 12); 1283b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1284b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp = readl(reg); 1285b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (lrmin) { 1286b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp &= ~(0xf << 8); 1287b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp |= lrmin; 1288b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1289b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (lrmax) { 1290b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp &= ~(0xf << 12); 1291b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp |= lrmax; 1292b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1293b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik writel(tmp, reg); 1294b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 1295b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1296b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1297b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case PHY_FUNC_HARD_RESET: 1298b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp = readl(reg); 1299b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (tmp & PHY_RST_HARD) 1300b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 1301b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik writel(tmp | PHY_RST_HARD, reg); 1302b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 1303b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1304b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case PHY_FUNC_LINK_RESET: 1305b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik writel(readl(reg) | PHY_RST, reg); 1306b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 1307b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1308b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case PHY_FUNC_DISABLE: 1309b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik case PHY_FUNC_RELEASE_SPINUP_HOLD: 1310b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik default: 1311b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = -EOPNOTSUPP; 1312b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1313b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1314b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 1315b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1316b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1317b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id) 1318b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1319b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_phy *phy = &mvi->phy[phy_id]; 1320b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct asd_sas_phy *sas_phy = &phy->sas_phy; 1321b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1322b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0; 1323b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_phy->class = SAS; 1324b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_phy->iproto = SAS_PROTOCOL_ALL; 1325b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_phy->tproto = 0; 1326b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_phy->type = PHY_TYPE_PHYSICAL; 1327b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_phy->role = PHY_ROLE_INITIATOR; 1328b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_phy->oob_mode = OOB_NOT_CONNECTED; 1329b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN; 1330b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1331b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_phy->id = phy_id; 1332b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_phy->sas_addr = &mvi->sas_addr[0]; 1333b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_phy->frame_rcvd = &phy->frame_rcvd[0]; 1334b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_phy->ha = &mvi->sas; 1335b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_phy->lldd_phy = phy; 1336b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1337b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1338b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev, 1339b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik const struct pci_device_id *ent) 1340b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1341b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_info *mvi; 1342b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik unsigned long res_start, res_len; 1343b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct asd_sas_phy **arr_phy; 1344b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct asd_sas_port **arr_port; 1345b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik const struct mvs_chip_info *chip = &mvs_chips[ent->driver_data]; 1346b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik int i; 1347b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1348b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* 1349b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * alloc and init our per-HBA mvs_info struct 1350b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 1351b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1352b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi = kzalloc(sizeof(*mvi), GFP_KERNEL); 1353b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!mvi) 1354b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return NULL; 1355b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1356b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik spin_lock_init(&mvi->lock); 1357b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->pdev = pdev; 1358b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->chip = chip; 1359b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1360b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (pdev->device == 0x6440 && pdev->revision == 0) 1361b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->flags |= MVF_PHY_PWR_FIX; 1362b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1363b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* 1364b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * alloc and init SCSI, SAS glue 1365b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 1366b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1367b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->shost = scsi_host_alloc(&mvs_sht, sizeof(void *)); 1368b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!mvi->shost) 1369b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 1370b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1371b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik arr_phy = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL); 1372b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik arr_port = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL); 1373b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!arr_phy || !arr_port) 1374b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 1375b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1376b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik for (i = 0; i < MVS_MAX_PHYS; i++) { 1377b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_phy_init(mvi, i); 1378b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik arr_phy[i] = &mvi->phy[i].sas_phy; 1379b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik arr_port[i] = &mvi->port[i].sas_port; 1380b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1381b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1382b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas; 1383b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->shost->transportt = mvs_stt; 1384b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->shost->max_id = ~0; 1385b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->shost->max_lun = ~0; 1386b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->shost->max_cmd_len = ~0; 1387b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1388b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->sas.sas_ha_name = DRV_NAME; 1389b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->sas.dev = &pdev->dev; 1390b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->sas.lldd_module = THIS_MODULE; 1391b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->sas.sas_addr = &mvi->sas_addr[0]; 1392b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->sas.sas_phy = arr_phy; 1393b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->sas.sas_port = arr_port; 1394b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->sas.num_phys = chip->n_phy; 1395b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->sas.lldd_max_execute_num = MVS_TX_RING_SZ - 1;/* FIXME: correct? */ 1396b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->sas.lldd_queue_size = MVS_TX_RING_SZ - 1; /* FIXME: correct? */ 1397b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->sas.lldd_ha = mvi; 1398b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->sas.core.shost = mvi->shost; 1399b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1400b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_tag_set(mvi, MVS_TX_RING_SZ - 1); 1401b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1402b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* 1403b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * ioremap main and peripheral registers 1404b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 1405b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1406b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik res_start = pci_resource_start(pdev, 2); 1407b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik res_len = pci_resource_len(pdev, 2); 1408b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!res_start || !res_len) 1409b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 1410b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1411b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->peri_regs = ioremap_nocache(res_start, res_len); 1412b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!mvi->regs) 1413b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 1414b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1415b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik res_start = pci_resource_start(pdev, 4); 1416b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik res_len = pci_resource_len(pdev, 4); 1417b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!res_start || !res_len) 1418b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 1419b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1420b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->regs = ioremap_nocache(res_start, res_len); 1421b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!mvi->regs) 1422b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 1423b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1424b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* 1425b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * alloc and init our DMA areas 1426b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 1427b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1428b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->tx = dma_alloc_coherent(&pdev->dev, 1429b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sizeof(*mvi->tx) * MVS_TX_RING_SZ, 1430b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik &mvi->tx_dma, GFP_KERNEL); 1431b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!mvi->tx) 1432b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 1433b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_TX_RING_SZ); 1434b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1435b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->rx_fis = dma_alloc_coherent(&pdev->dev, MVS_RX_FISL_SZ, 1436b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik &mvi->rx_fis_dma, GFP_KERNEL); 1437b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!mvi->rx_fis) 1438b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 1439b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ); 1440b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1441b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->rx = dma_alloc_coherent(&pdev->dev, 1442b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sizeof(*mvi->rx) * MVS_RX_RING_SZ, 1443b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik &mvi->rx_dma, GFP_KERNEL); 1444b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!mvi->rx) 1445b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 1446b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memset(mvi->rx, 0, sizeof(*mvi->rx) * MVS_RX_RING_SZ); 1447b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1448b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->rx[0] = cpu_to_le32(0xfff); 1449b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->rx_cons = 0xfff; 1450b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1451b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->slot = dma_alloc_coherent(&pdev->dev, 1452b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sizeof(*mvi->slot) * MVS_SLOTS, 1453b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik &mvi->slot_dma, GFP_KERNEL); 1454b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!mvi->slot) 1455b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 1456b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memset(mvi->slot, 0, sizeof(*mvi->slot) * MVS_SLOTS); 1457b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1458b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik for (i = 0; i < MVS_SLOTS; i++) { 1459b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_slot_info *slot = &mvi->slot_info[i]; 1460b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1461b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik slot->buf = dma_alloc_coherent(&pdev->dev, MVS_SLOT_BUF_SZ, 1462b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik &slot->buf_dma, GFP_KERNEL); 1463b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!slot->buf) 1464b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 1465b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memset(slot->buf, 0, MVS_SLOT_BUF_SZ); 1466b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1467b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1468b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* finally, read NVRAM to get our SAS address */ 1469b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (mvs_nvram_read(mvi, NVR_SAS_ADDR, &mvi->sas_addr, 8)) 1470b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 1471b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1472b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return mvi; 1473b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1474b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out: 1475b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_free(mvi); 1476b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return NULL; 1477b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1478b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1479b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic u32 mvs_cr32(void __iomem *regs, u32 addr) 1480b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1481b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(CMD_ADDR, addr); 1482b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return mr32(CMD_DATA); 1483b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1484b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1485b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_cw32(void __iomem *regs, u32 addr, u32 val) 1486b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1487b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(CMD_ADDR, addr); 1488b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(CMD_DATA, val); 1489b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1490b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1491b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#if 0 1492b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic u32 mvs_phy_read(struct mvs_info *mvi, unsigned int phy_id, u32 addr) 1493b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1494b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void __iomem *regs = mvi->regs; 1495b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void __iomem *phy_regs = regs + MVS_P0_CFG_ADDR + (phy_id * 8); 1496b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1497b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik writel(addr, phy_regs); 1498b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return readl(phy_regs + 4); 1499b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1500b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#endif 1501b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1502b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_phy_write(struct mvs_info *mvi, unsigned int phy_id, 1503b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 addr, u32 val) 1504b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1505b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void __iomem *regs = mvi->regs; 1506b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void __iomem *phy_regs = regs + MVS_P0_CFG_ADDR + (phy_id * 8); 1507b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1508b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik writel(addr, phy_regs); 1509b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik writel(val, phy_regs + 4); 1510b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik readl(phy_regs); /* flush */ 1511b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1512b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1513b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void __devinit mvs_phy_hacks(struct mvs_info *mvi) 1514b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1515b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void __iomem *regs = mvi->regs; 1516b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 tmp; 1517b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1518b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* workaround for SATA R-ERR, to ignore phy glitch */ 1519b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp = mvs_cr32(regs, CMD_PHY_TIMER); 1520b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp &= ~(1 << 9); 1521b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp |= (1 << 10); 1522b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_cw32(regs, CMD_PHY_TIMER, tmp); 1523b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1524b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* enable retry 127 times */ 1525b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_cw32(regs, CMD_SAS_CTL1, 0x7f7f); 1526b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1527b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* extend open frame timeout to max */ 1528b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp = mvs_cr32(regs, CMD_SAS_CTL0); 1529b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp &= ~0xffff; 1530b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp |= 0x3fff; 1531b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_cw32(regs, CMD_SAS_CTL0, tmp); 1532b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1533b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* workaround for WDTIMEOUT , set to 550 ms */ 1534b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_cw32(regs, CMD_WD_TIMER, 0xffffff); 1535b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1536b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* not to halt for different port op during wideport link change */ 1537b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d); 1538b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1539b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* workaround for Seagate disk not-found OOB sequence, recv 1540b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * COMINIT before sending out COMWAKE */ 1541b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp = mvs_cr32(regs, CMD_PHY_MODE_21); 1542b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp &= 0x0000ffff; 1543b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp |= 0x00fa0000; 1544b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_cw32(regs, CMD_PHY_MODE_21, tmp); 1545b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1546b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp = mvs_cr32(regs, CMD_PHY_TIMER); 1547b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp &= 0x1fffffff; 1548b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp |= (2U << 29); /* 8 ms retry */ 1549b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_cw32(regs, CMD_PHY_TIMER, tmp); 1550b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1551b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1552b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int __devinit mvs_hw_init(struct mvs_info *mvi) 1553b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1554b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void __iomem *regs = mvi->regs; 1555b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik int i; 1556b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 tmp, cctl; 1557b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1558b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* make sure interrupts are masked immediately (paranoia) */ 1559b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(GBL_CTL, 0); 1560b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp = mr32(GBL_CTL); 1561b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1562b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!(tmp & HBA_RST)) { 1563b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (mvi->flags & MVF_PHY_PWR_FIX) { 1564b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp); 1565b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp &= ~PCTL_PWR_ON; 1566b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp |= PCTL_OFF; 1567b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); 1568b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1569b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp); 1570b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp &= ~PCTL_PWR_ON; 1571b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp |= PCTL_OFF; 1572b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); 1573b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1574b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1575b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* global reset, incl. COMRESET/H_RESET_N (self-clearing) */ 1576b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32_f(GBL_CTL, HBA_RST); 1577b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1578b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1579b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1580b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* wait for reset to finish; timeout is just a guess */ 1581b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik i = 1000; 1582b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik while (i-- > 0) { 1583b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik msleep(10); 1584b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1585b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!(mr32(GBL_CTL) & HBA_RST)) 1586b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik break; 1587b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1588b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (mr32(GBL_CTL) & HBA_RST) { 1589b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dev_printk(KERN_ERR, &mvi->pdev->dev, "HBA reset failed\n"); 1590b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return -EBUSY; 1591b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1592b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1593b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* make sure RST is set; HBA_RST /should/ have done that for us */ 1594b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik cctl = mr32(CTL); 1595b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (cctl & CCTL_RST) 1596b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik cctl &= ~CCTL_RST; 1597b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik else 1598b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32_f(CTL, cctl | CCTL_RST); 1599b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1600b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp); 1601b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp |= PCTL_PWR_ON; 1602b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp &= ~PCTL_OFF; 1603b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); 1604b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1605b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp); 1606b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp |= PCTL_PWR_ON; 1607b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp &= ~PCTL_OFF; 1608b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); 1609b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1610b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32_f(CTL, cctl); 1611b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1612b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_phy_hacks(mvi); 1613b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1614b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(CMD_LIST_LO, mvi->slot_dma); 1615b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16); 1616b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1617b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(RX_FIS_LO, mvi->rx_fis_dma); 1618b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16); 1619b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1620b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(TX_CFG, MVS_TX_RING_SZ); 1621b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(TX_LO, mvi->tx_dma); 1622b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(TX_HI, (mvi->tx_dma >> 16) >> 16); 1623b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1624b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(RX_CFG, MVS_RX_RING_SZ); 1625b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(RX_LO, mvi->rx_dma); 1626b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(RX_HI, (mvi->rx_dma >> 16) >> 16); 1627b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1628b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* init and reset phys */ 1629b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik for (i = 0; i < mvi->chip->n_phy; i++) { 1630b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* FIXME: is this the correct dword order? */ 1631b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 lo = *((u32 *) &mvi->sas_addr[0]); 1632b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 hi = *((u32 *) &mvi->sas_addr[4]); 1633b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1634b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* set phy local SAS address */ 1635b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_phy_write(mvi, i, PHYR_ADDR_LO, lo); 1636b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_phy_write(mvi, i, PHYR_ADDR_HI, hi); 1637b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1638b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* reset phy */ 1639b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp = readl(regs + MVS_P0_SER_CTLSTAT + (i * 4)); 1640b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp |= PHY_RST; 1641b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik writel(tmp, regs + MVS_P0_SER_CTLSTAT + (i * 4)); 1642b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1643b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1644b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik msleep(100); 1645b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1646b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik for (i = 0; i < mvi->chip->n_phy; i++) { 1647b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* set phy int mask */ 1648b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik writel(PHYEV_BROAD_CH | PHYEV_RDY_CH, 1649b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik regs + MVS_P0_INT_MASK + (i * 8)); 1650b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1651b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* clear phy int status */ 1652b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik tmp = readl(regs + MVS_P0_INT_STAT + (i * 8)); 1653b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik writel(tmp, regs + MVS_P0_INT_STAT + (i * 8)); 1654b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1655b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1656b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* FIXME: update wide port bitmaps */ 1657b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1658b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* ladies and gentlemen, start your engines */ 1659b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(TX_CFG, MVS_TX_RING_SZ | TX_EN); 1660b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(RX_CFG, MVS_RX_RING_SZ | RX_EN); 1661b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | PCS_CMD_EN | 1662b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik ((mvi->flags & MVF_MSI) ? PCS_SELF_CLEAR : 0)); 1663b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1664b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* re-enable interrupts globally */ 1665b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mw32(GBL_CTL, INT_EN); 1666b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1667b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 1668b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1669b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1670b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void __devinit mvs_print_info(struct mvs_info *mvi) 1671b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1672b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct pci_dev *pdev = mvi->pdev; 1673b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik static int printed_version; 1674b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1675b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!printed_version++) 1676b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); 1677b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1678b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dev_printk(KERN_INFO, &pdev->dev, "%u phys, addr %llx\n", 1679b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->chip->n_phy, SAS_ADDR(mvi->sas_addr)); 1680b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1681b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1682b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int __devinit mvs_pci_init(struct pci_dev *pdev, 1683b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik const struct pci_device_id *ent) 1684b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1685b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik int rc; 1686b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_info *mvi; 1687b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik irq_handler_t irq_handler = mvs_interrupt; 1688b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1689b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = pci_enable_device(pdev); 1690b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) 1691b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 1692b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1693b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_set_master(pdev); 1694b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1695b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = pci_request_regions(pdev, DRV_NAME); 1696b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) 1697b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out_disable; 1698b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1699b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = pci_go_64(pdev); 1700b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) 1701b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out_regions; 1702b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1703b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi = mvs_alloc(pdev, ent); 1704b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!mvi) { 1705b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = -ENOMEM; 1706b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out_regions; 1707b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1708b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1709b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = mvs_hw_init(mvi); 1710b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) 1711b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out_mvi; 1712b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1713b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!pci_enable_msi(pdev)) { 1714b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvi->flags |= MVF_MSI; 1715b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik irq_handler = mvs_msi_interrupt; 1716b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1717b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1718b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME, mvi); 1719b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) 1720b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out_msi; 1721b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1722b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = scsi_add_host(mvi->shost, &pdev->dev); 1723b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) 1724b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out_irq; 1725b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1726b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = sas_register_ha(&mvi->sas); 1727b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) 1728b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out_shost; 1729b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1730b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_set_drvdata(pdev, mvi); 1731b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1732b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_print_info(mvi); 1733b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1734b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik scsi_scan_host(mvi->shost); 1735b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 1736b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1737b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_shost: 1738b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik scsi_remove_host(mvi->shost); 1739b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_irq: 1740b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik free_irq(pdev->irq, mvi); 1741b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_msi: 1742b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (mvi->flags |= MVF_MSI) 1743b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_disable_msi(pdev); 1744b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_mvi: 1745b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_free(mvi); 1746b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_regions: 1747b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_release_regions(pdev); 1748b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_disable: 1749b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_disable_device(pdev); 1750b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 1751b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1752b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1753b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void __devexit mvs_pci_remove(struct pci_dev *pdev) 1754b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1755b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_info *mvi = pci_get_drvdata(pdev); 1756b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1757b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_set_drvdata(pdev, NULL); 1758b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1759b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_unregister_ha(&mvi->sas); 1760b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_remove_host(mvi->shost); 1761b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik scsi_remove_host(mvi->shost); 1762b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1763b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik free_irq(pdev->irq, mvi); 1764b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (mvi->flags & MVF_MSI) 1765b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_disable_msi(pdev); 1766b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_free(mvi); 1767b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_release_regions(pdev); 1768b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_disable_device(pdev); 1769b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1770b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1771b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct sas_domain_function_template mvs_transport_ops = { 1772b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .lldd_execute_task = mvs_task_exec, 1773b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .lldd_control_phy = mvs_phy_control, 1774b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 1775b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1776b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct pci_device_id __devinitdata mvs_pci_table[] = { 1777b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik { PCI_VDEVICE(MARVELL, 0x6320), chip_6320 }, 1778b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik { PCI_VDEVICE(MARVELL, 0x6340), chip_6440 }, 1779b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik { PCI_VDEVICE(MARVELL, 0x6440), chip_6440 }, 1780b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik { PCI_VDEVICE(MARVELL, 0x6480), chip_6480 }, 1781b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1782b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik { } /* terminate list */ 1783b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 1784b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1785b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct pci_driver mvs_pci_driver = { 1786b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .name = DRV_NAME, 1787b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .id_table = mvs_pci_table, 1788b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .probe = mvs_pci_init, 1789b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik .remove = __devexit_p(mvs_pci_remove), 1790b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}; 1791b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1792b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int __init mvs_init(void) 1793b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1794b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik int rc; 1795b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1796b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik mvs_stt = sas_domain_attach_transport(&mvs_transport_ops); 1797b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (!mvs_stt) 1798b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return -ENOMEM; 1799b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1800b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik rc = pci_register_driver(&mvs_pci_driver); 1801b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (rc) 1802b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik goto err_out; 1803b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1804b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 1805b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1806b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out: 1807b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_release_transport(mvs_stt); 1808b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 1809b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1810b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1811b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void __exit mvs_exit(void) 1812b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 1813b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik pci_unregister_driver(&mvs_pci_driver); 1814b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik sas_release_transport(mvs_stt); 1815b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1816b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1817b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikmodule_init(mvs_init); 1818b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikmodule_exit(mvs_exit); 1819b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1820b5762948263dd5e9725a380e7a9626f99e40ae9dJeff GarzikMODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>"); 1821b5762948263dd5e9725a380e7a9626f99e40ae9dJeff GarzikMODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver"); 1822b5762948263dd5e9725a380e7a9626f99e40ae9dJeff GarzikMODULE_VERSION(DRV_VERSION); 1823b5762948263dd5e9725a380e7a9626f99e40ae9dJeff GarzikMODULE_LICENSE("GPL"); 1824b5762948263dd5e9725a380e7a9626f99e40ae9dJeff GarzikMODULE_DEVICE_TABLE(pci, mvs_pci_table); 1825b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1826