18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AMD am53c974 driver. 48c2ecf20Sopenharmony_ci * Copyright (c) 2014 Hannes Reinecke, SUSE Linux GmbH 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/pci.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "esp_scsi.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define DRV_MODULE_NAME "am53c974" 198c2ecf20Sopenharmony_ci#define DRV_MODULE_VERSION "1.00" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic bool am53c974_debug; 228c2ecf20Sopenharmony_cistatic bool am53c974_fenab = true; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define esp_dma_log(f, a...) \ 258c2ecf20Sopenharmony_ci do { \ 268c2ecf20Sopenharmony_ci if (am53c974_debug) \ 278c2ecf20Sopenharmony_ci shost_printk(KERN_DEBUG, esp->host, f, ##a); \ 288c2ecf20Sopenharmony_ci } while (0) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define ESP_DMA_CMD 0x10 318c2ecf20Sopenharmony_ci#define ESP_DMA_STC 0x11 328c2ecf20Sopenharmony_ci#define ESP_DMA_SPA 0x12 338c2ecf20Sopenharmony_ci#define ESP_DMA_WBC 0x13 348c2ecf20Sopenharmony_ci#define ESP_DMA_WAC 0x14 358c2ecf20Sopenharmony_ci#define ESP_DMA_STATUS 0x15 368c2ecf20Sopenharmony_ci#define ESP_DMA_SMDLA 0x16 378c2ecf20Sopenharmony_ci#define ESP_DMA_WMAC 0x17 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define ESP_DMA_CMD_IDLE 0x00 408c2ecf20Sopenharmony_ci#define ESP_DMA_CMD_BLAST 0x01 418c2ecf20Sopenharmony_ci#define ESP_DMA_CMD_ABORT 0x02 428c2ecf20Sopenharmony_ci#define ESP_DMA_CMD_START 0x03 438c2ecf20Sopenharmony_ci#define ESP_DMA_CMD_MASK 0x03 448c2ecf20Sopenharmony_ci#define ESP_DMA_CMD_DIAG 0x04 458c2ecf20Sopenharmony_ci#define ESP_DMA_CMD_MDL 0x10 468c2ecf20Sopenharmony_ci#define ESP_DMA_CMD_INTE_P 0x20 478c2ecf20Sopenharmony_ci#define ESP_DMA_CMD_INTE_D 0x40 488c2ecf20Sopenharmony_ci#define ESP_DMA_CMD_DIR 0x80 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define ESP_DMA_STAT_PWDN 0x01 518c2ecf20Sopenharmony_ci#define ESP_DMA_STAT_ERROR 0x02 528c2ecf20Sopenharmony_ci#define ESP_DMA_STAT_ABORT 0x04 538c2ecf20Sopenharmony_ci#define ESP_DMA_STAT_DONE 0x08 548c2ecf20Sopenharmony_ci#define ESP_DMA_STAT_SCSIINT 0x10 558c2ecf20Sopenharmony_ci#define ESP_DMA_STAT_BCMPLT 0x20 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* EEPROM is accessed with 16-bit values */ 588c2ecf20Sopenharmony_ci#define DC390_EEPROM_READ 0x80 598c2ecf20Sopenharmony_ci#define DC390_EEPROM_LEN 0x40 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * DC390 EEPROM 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * 8 * 4 bytes of per-device options 658c2ecf20Sopenharmony_ci * followed by HBA specific options 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Per-device options */ 698c2ecf20Sopenharmony_ci#define DC390_EE_MODE1 0x00 708c2ecf20Sopenharmony_ci#define DC390_EE_SPEED 0x01 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* HBA-specific options */ 738c2ecf20Sopenharmony_ci#define DC390_EE_ADAPT_SCSI_ID 0x40 748c2ecf20Sopenharmony_ci#define DC390_EE_MODE2 0x41 758c2ecf20Sopenharmony_ci#define DC390_EE_DELAY 0x42 768c2ecf20Sopenharmony_ci#define DC390_EE_TAG_CMD_NUM 0x43 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#define DC390_EE_MODE1_PARITY_CHK 0x01 798c2ecf20Sopenharmony_ci#define DC390_EE_MODE1_SYNC_NEGO 0x02 808c2ecf20Sopenharmony_ci#define DC390_EE_MODE1_EN_DISC 0x04 818c2ecf20Sopenharmony_ci#define DC390_EE_MODE1_SEND_START 0x08 828c2ecf20Sopenharmony_ci#define DC390_EE_MODE1_TCQ 0x10 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define DC390_EE_MODE2_MORE_2DRV 0x01 858c2ecf20Sopenharmony_ci#define DC390_EE_MODE2_GREATER_1G 0x02 868c2ecf20Sopenharmony_ci#define DC390_EE_MODE2_RST_SCSI_BUS 0x04 878c2ecf20Sopenharmony_ci#define DC390_EE_MODE2_ACTIVE_NEGATION 0x08 888c2ecf20Sopenharmony_ci#define DC390_EE_MODE2_NO_SEEK 0x10 898c2ecf20Sopenharmony_ci#define DC390_EE_MODE2_LUN_CHECK 0x20 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistruct pci_esp_priv { 928c2ecf20Sopenharmony_ci struct esp *esp; 938c2ecf20Sopenharmony_ci u8 dma_status; 948c2ecf20Sopenharmony_ci}; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void pci_esp_dma_drain(struct esp *esp); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic inline struct pci_esp_priv *pci_esp_get_priv(struct esp *esp) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci return dev_get_drvdata(esp->dev); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic void pci_esp_write8(struct esp *esp, u8 val, unsigned long reg) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci iowrite8(val, esp->regs + (reg * 4UL)); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic u8 pci_esp_read8(struct esp *esp, unsigned long reg) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci return ioread8(esp->regs + (reg * 4UL)); 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic void pci_esp_write32(struct esp *esp, u32 val, unsigned long reg) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci return iowrite32(val, esp->regs + (reg * 4UL)); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic int pci_esp_irq_pending(struct esp *esp) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci struct pci_esp_priv *pep = pci_esp_get_priv(esp); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci pep->dma_status = pci_esp_read8(esp, ESP_DMA_STATUS); 1238c2ecf20Sopenharmony_ci esp_dma_log("dma intr dreg[%02x]\n", pep->dma_status); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (pep->dma_status & (ESP_DMA_STAT_ERROR | 1268c2ecf20Sopenharmony_ci ESP_DMA_STAT_ABORT | 1278c2ecf20Sopenharmony_ci ESP_DMA_STAT_DONE | 1288c2ecf20Sopenharmony_ci ESP_DMA_STAT_SCSIINT)) 1298c2ecf20Sopenharmony_ci return 1; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return 0; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic void pci_esp_reset_dma(struct esp *esp) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci /* Nothing to do ? */ 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic void pci_esp_dma_drain(struct esp *esp) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci u8 resid; 1428c2ecf20Sopenharmony_ci int lim = 1000; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if ((esp->sreg & ESP_STAT_PMASK) == ESP_DOP || 1468c2ecf20Sopenharmony_ci (esp->sreg & ESP_STAT_PMASK) == ESP_DIP) 1478c2ecf20Sopenharmony_ci /* Data-In or Data-Out, nothing to be done */ 1488c2ecf20Sopenharmony_ci return; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci while (--lim > 0) { 1518c2ecf20Sopenharmony_ci resid = pci_esp_read8(esp, ESP_FFLAGS) & ESP_FF_FBYTES; 1528c2ecf20Sopenharmony_ci if (resid <= 1) 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci cpu_relax(); 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* 1588c2ecf20Sopenharmony_ci * When there is a residual BCMPLT will never be set 1598c2ecf20Sopenharmony_ci * (obviously). But we still have to issue the BLAST 1608c2ecf20Sopenharmony_ci * command, otherwise the data will not being transferred. 1618c2ecf20Sopenharmony_ci * But we'll never know when the BLAST operation is 1628c2ecf20Sopenharmony_ci * finished. So check for some time and give up eventually. 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_ci lim = 1000; 1658c2ecf20Sopenharmony_ci pci_esp_write8(esp, ESP_DMA_CMD_DIR | ESP_DMA_CMD_BLAST, ESP_DMA_CMD); 1668c2ecf20Sopenharmony_ci while (pci_esp_read8(esp, ESP_DMA_STATUS) & ESP_DMA_STAT_BCMPLT) { 1678c2ecf20Sopenharmony_ci if (--lim == 0) 1688c2ecf20Sopenharmony_ci break; 1698c2ecf20Sopenharmony_ci cpu_relax(); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci pci_esp_write8(esp, ESP_DMA_CMD_DIR | ESP_DMA_CMD_IDLE, ESP_DMA_CMD); 1728c2ecf20Sopenharmony_ci esp_dma_log("DMA blast done (%d tries, %d bytes left)\n", lim, resid); 1738c2ecf20Sopenharmony_ci /* BLAST residual handling is currently untested */ 1748c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(resid == 1)) { 1758c2ecf20Sopenharmony_ci struct esp_cmd_entry *ent = esp->active_cmd; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci ent->flags |= ESP_CMD_FLAG_RESIDUAL; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void pci_esp_dma_invalidate(struct esp *esp) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct pci_esp_priv *pep = pci_esp_get_priv(esp); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci esp_dma_log("invalidate DMA\n"); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci pci_esp_write8(esp, ESP_DMA_CMD_IDLE, ESP_DMA_CMD); 1888c2ecf20Sopenharmony_ci pep->dma_status = 0; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic int pci_esp_dma_error(struct esp *esp) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct pci_esp_priv *pep = pci_esp_get_priv(esp); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (pep->dma_status & ESP_DMA_STAT_ERROR) { 1968c2ecf20Sopenharmony_ci u8 dma_cmd = pci_esp_read8(esp, ESP_DMA_CMD); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if ((dma_cmd & ESP_DMA_CMD_MASK) == ESP_DMA_CMD_START) 1998c2ecf20Sopenharmony_ci pci_esp_write8(esp, ESP_DMA_CMD_ABORT, ESP_DMA_CMD); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci return 1; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci if (pep->dma_status & ESP_DMA_STAT_ABORT) { 2048c2ecf20Sopenharmony_ci pci_esp_write8(esp, ESP_DMA_CMD_IDLE, ESP_DMA_CMD); 2058c2ecf20Sopenharmony_ci pep->dma_status = pci_esp_read8(esp, ESP_DMA_CMD); 2068c2ecf20Sopenharmony_ci return 1; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic void pci_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, 2128c2ecf20Sopenharmony_ci u32 dma_count, int write, u8 cmd) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct pci_esp_priv *pep = pci_esp_get_priv(esp); 2158c2ecf20Sopenharmony_ci u32 val = 0; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci BUG_ON(!(cmd & ESP_CMD_DMA)); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci pep->dma_status = 0; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* Set DMA engine to IDLE */ 2228c2ecf20Sopenharmony_ci if (write) 2238c2ecf20Sopenharmony_ci /* DMA write direction logic is inverted */ 2248c2ecf20Sopenharmony_ci val |= ESP_DMA_CMD_DIR; 2258c2ecf20Sopenharmony_ci pci_esp_write8(esp, ESP_DMA_CMD_IDLE | val, ESP_DMA_CMD); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci pci_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); 2288c2ecf20Sopenharmony_ci pci_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); 2298c2ecf20Sopenharmony_ci if (esp->config2 & ESP_CONFIG2_FENAB) 2308c2ecf20Sopenharmony_ci pci_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci pci_esp_write32(esp, esp_count, ESP_DMA_STC); 2338c2ecf20Sopenharmony_ci pci_esp_write32(esp, addr, ESP_DMA_SPA); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci esp_dma_log("start dma addr[%x] count[%d:%d]\n", 2368c2ecf20Sopenharmony_ci addr, esp_count, dma_count); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci scsi_esp_cmd(esp, cmd); 2398c2ecf20Sopenharmony_ci /* Send DMA Start command */ 2408c2ecf20Sopenharmony_ci pci_esp_write8(esp, ESP_DMA_CMD_START | val, ESP_DMA_CMD); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic u32 pci_esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci int dma_limit = 16; 2468c2ecf20Sopenharmony_ci u32 base, end; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* 2498c2ecf20Sopenharmony_ci * If CONFIG2_FENAB is set we can 2508c2ecf20Sopenharmony_ci * handle up to 24 bit addresses 2518c2ecf20Sopenharmony_ci */ 2528c2ecf20Sopenharmony_ci if (esp->config2 & ESP_CONFIG2_FENAB) 2538c2ecf20Sopenharmony_ci dma_limit = 24; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (dma_len > (1U << dma_limit)) 2568c2ecf20Sopenharmony_ci dma_len = (1U << dma_limit); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* 2598c2ecf20Sopenharmony_ci * Prevent crossing a 24-bit address boundary. 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_ci base = dma_addr & ((1U << 24) - 1U); 2628c2ecf20Sopenharmony_ci end = base + dma_len; 2638c2ecf20Sopenharmony_ci if (end > (1U << 24)) 2648c2ecf20Sopenharmony_ci end = (1U <<24); 2658c2ecf20Sopenharmony_ci dma_len = end - base; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return dma_len; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic const struct esp_driver_ops pci_esp_ops = { 2718c2ecf20Sopenharmony_ci .esp_write8 = pci_esp_write8, 2728c2ecf20Sopenharmony_ci .esp_read8 = pci_esp_read8, 2738c2ecf20Sopenharmony_ci .irq_pending = pci_esp_irq_pending, 2748c2ecf20Sopenharmony_ci .reset_dma = pci_esp_reset_dma, 2758c2ecf20Sopenharmony_ci .dma_drain = pci_esp_dma_drain, 2768c2ecf20Sopenharmony_ci .dma_invalidate = pci_esp_dma_invalidate, 2778c2ecf20Sopenharmony_ci .send_dma_cmd = pci_esp_send_dma_cmd, 2788c2ecf20Sopenharmony_ci .dma_error = pci_esp_dma_error, 2798c2ecf20Sopenharmony_ci .dma_length_limit = pci_esp_dma_length_limit, 2808c2ecf20Sopenharmony_ci}; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* 2838c2ecf20Sopenharmony_ci * Read DC-390 eeprom 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_cistatic void dc390_eeprom_prepare_read(struct pci_dev *pdev, u8 cmd) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci u8 carry_flag = 1, j = 0x80, bval; 2888c2ecf20Sopenharmony_ci int i; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci for (i = 0; i < 9; i++) { 2918c2ecf20Sopenharmony_ci if (carry_flag) { 2928c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, 0x80, 0x40); 2938c2ecf20Sopenharmony_ci bval = 0xc0; 2948c2ecf20Sopenharmony_ci } else 2958c2ecf20Sopenharmony_ci bval = 0x80; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci udelay(160); 2988c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, 0x80, bval); 2998c2ecf20Sopenharmony_ci udelay(160); 3008c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, 0x80, 0); 3018c2ecf20Sopenharmony_ci udelay(160); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci carry_flag = (cmd & j) ? 1 : 0; 3048c2ecf20Sopenharmony_ci j >>= 1; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic u16 dc390_eeprom_get_data(struct pci_dev *pdev) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci int i; 3118c2ecf20Sopenharmony_ci u16 wval = 0; 3128c2ecf20Sopenharmony_ci u8 bval; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 3158c2ecf20Sopenharmony_ci wval <<= 1; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, 0x80, 0x80); 3188c2ecf20Sopenharmony_ci udelay(160); 3198c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, 0x80, 0x40); 3208c2ecf20Sopenharmony_ci udelay(160); 3218c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, 0x00, &bval); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (bval == 0x22) 3248c2ecf20Sopenharmony_ci wval |= 1; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci return wval; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic void dc390_read_eeprom(struct pci_dev *pdev, u16 *ptr) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci u8 cmd = DC390_EEPROM_READ, i; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci for (i = 0; i < DC390_EEPROM_LEN; i++) { 3358c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, 0xc0, 0); 3368c2ecf20Sopenharmony_ci udelay(160); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci dc390_eeprom_prepare_read(pdev, cmd++); 3398c2ecf20Sopenharmony_ci *ptr++ = dc390_eeprom_get_data(pdev); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, 0x80, 0); 3428c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, 0x80, 0); 3438c2ecf20Sopenharmony_ci udelay(160); 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic void dc390_check_eeprom(struct esp *esp) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(esp->dev); 3508c2ecf20Sopenharmony_ci u8 EEbuf[128]; 3518c2ecf20Sopenharmony_ci u16 *ptr = (u16 *)EEbuf, wval = 0; 3528c2ecf20Sopenharmony_ci int i; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci dc390_read_eeprom(pdev, ptr); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci for (i = 0; i < DC390_EEPROM_LEN; i++, ptr++) 3578c2ecf20Sopenharmony_ci wval += *ptr; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* no Tekram EEprom found */ 3608c2ecf20Sopenharmony_ci if (wval != 0x1234) { 3618c2ecf20Sopenharmony_ci dev_printk(KERN_INFO, &pdev->dev, 3628c2ecf20Sopenharmony_ci "No valid Tekram EEprom found\n"); 3638c2ecf20Sopenharmony_ci return; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci esp->scsi_id = EEbuf[DC390_EE_ADAPT_SCSI_ID]; 3668c2ecf20Sopenharmony_ci esp->num_tags = 2 << EEbuf[DC390_EE_TAG_CMD_NUM]; 3678c2ecf20Sopenharmony_ci if (EEbuf[DC390_EE_MODE2] & DC390_EE_MODE2_ACTIVE_NEGATION) 3688c2ecf20Sopenharmony_ci esp->config4 |= ESP_CONFIG4_RADE | ESP_CONFIG4_RAE; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic int pci_esp_probe_one(struct pci_dev *pdev, 3728c2ecf20Sopenharmony_ci const struct pci_device_id *id) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci struct scsi_host_template *hostt = &scsi_esp_template; 3758c2ecf20Sopenharmony_ci int err = -ENODEV; 3768c2ecf20Sopenharmony_ci struct Scsi_Host *shost; 3778c2ecf20Sopenharmony_ci struct esp *esp; 3788c2ecf20Sopenharmony_ci struct pci_esp_priv *pep; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) { 3818c2ecf20Sopenharmony_ci dev_printk(KERN_INFO, &pdev->dev, "cannot enable device\n"); 3828c2ecf20Sopenharmony_ci return -ENODEV; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { 3868c2ecf20Sopenharmony_ci dev_printk(KERN_INFO, &pdev->dev, 3878c2ecf20Sopenharmony_ci "failed to set 32bit DMA mask\n"); 3888c2ecf20Sopenharmony_ci goto fail_disable_device; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci shost = scsi_host_alloc(hostt, sizeof(struct esp)); 3928c2ecf20Sopenharmony_ci if (!shost) { 3938c2ecf20Sopenharmony_ci dev_printk(KERN_INFO, &pdev->dev, 3948c2ecf20Sopenharmony_ci "failed to allocate scsi host\n"); 3958c2ecf20Sopenharmony_ci err = -ENOMEM; 3968c2ecf20Sopenharmony_ci goto fail_disable_device; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci pep = kzalloc(sizeof(struct pci_esp_priv), GFP_KERNEL); 4008c2ecf20Sopenharmony_ci if (!pep) { 4018c2ecf20Sopenharmony_ci dev_printk(KERN_INFO, &pdev->dev, 4028c2ecf20Sopenharmony_ci "failed to allocate esp_priv\n"); 4038c2ecf20Sopenharmony_ci err = -ENOMEM; 4048c2ecf20Sopenharmony_ci goto fail_host_alloc; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci esp = shost_priv(shost); 4088c2ecf20Sopenharmony_ci esp->host = shost; 4098c2ecf20Sopenharmony_ci esp->dev = &pdev->dev; 4108c2ecf20Sopenharmony_ci esp->ops = &pci_esp_ops; 4118c2ecf20Sopenharmony_ci /* 4128c2ecf20Sopenharmony_ci * The am53c974 HBA has a design flaw of generating 4138c2ecf20Sopenharmony_ci * spurious DMA completion interrupts when using 4148c2ecf20Sopenharmony_ci * DMA for command submission. 4158c2ecf20Sopenharmony_ci */ 4168c2ecf20Sopenharmony_ci esp->flags |= ESP_FLAG_USE_FIFO; 4178c2ecf20Sopenharmony_ci /* 4188c2ecf20Sopenharmony_ci * Enable CONFIG2_FENAB to allow for large DMA transfers 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_ci if (am53c974_fenab) 4218c2ecf20Sopenharmony_ci esp->config2 |= ESP_CONFIG2_FENAB; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci pep->esp = esp; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (pci_request_regions(pdev, DRV_MODULE_NAME)) { 4268c2ecf20Sopenharmony_ci dev_printk(KERN_ERR, &pdev->dev, 4278c2ecf20Sopenharmony_ci "pci memory selection failed\n"); 4288c2ecf20Sopenharmony_ci goto fail_priv_alloc; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci esp->regs = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); 4328c2ecf20Sopenharmony_ci if (!esp->regs) { 4338c2ecf20Sopenharmony_ci dev_printk(KERN_ERR, &pdev->dev, "pci I/O map failed\n"); 4348c2ecf20Sopenharmony_ci err = -EINVAL; 4358c2ecf20Sopenharmony_ci goto fail_release_regions; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci esp->dma_regs = esp->regs; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci pci_set_master(pdev); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci esp->command_block = dma_alloc_coherent(&pdev->dev, 16, 4428c2ecf20Sopenharmony_ci &esp->command_block_dma, GFP_KERNEL); 4438c2ecf20Sopenharmony_ci if (!esp->command_block) { 4448c2ecf20Sopenharmony_ci dev_printk(KERN_ERR, &pdev->dev, 4458c2ecf20Sopenharmony_ci "failed to allocate command block\n"); 4468c2ecf20Sopenharmony_ci err = -ENOMEM; 4478c2ecf20Sopenharmony_ci goto fail_unmap_regs; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, pep); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci err = request_irq(pdev->irq, scsi_esp_intr, IRQF_SHARED, 4538c2ecf20Sopenharmony_ci DRV_MODULE_NAME, esp); 4548c2ecf20Sopenharmony_ci if (err < 0) { 4558c2ecf20Sopenharmony_ci dev_printk(KERN_ERR, &pdev->dev, "failed to register IRQ\n"); 4568c2ecf20Sopenharmony_ci goto fail_unmap_command_block; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci esp->scsi_id = 7; 4608c2ecf20Sopenharmony_ci dc390_check_eeprom(esp); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci shost->this_id = esp->scsi_id; 4638c2ecf20Sopenharmony_ci shost->max_id = 8; 4648c2ecf20Sopenharmony_ci shost->irq = pdev->irq; 4658c2ecf20Sopenharmony_ci shost->io_port = pci_resource_start(pdev, 0); 4668c2ecf20Sopenharmony_ci shost->n_io_port = pci_resource_len(pdev, 0); 4678c2ecf20Sopenharmony_ci shost->unique_id = shost->io_port; 4688c2ecf20Sopenharmony_ci esp->scsi_id_mask = (1 << esp->scsi_id); 4698c2ecf20Sopenharmony_ci /* Assume 40MHz clock */ 4708c2ecf20Sopenharmony_ci esp->cfreq = 40000000; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci err = scsi_esp_register(esp); 4738c2ecf20Sopenharmony_ci if (err) 4748c2ecf20Sopenharmony_ci goto fail_free_irq; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return 0; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cifail_free_irq: 4798c2ecf20Sopenharmony_ci free_irq(pdev->irq, esp); 4808c2ecf20Sopenharmony_cifail_unmap_command_block: 4818c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 4828c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, 16, esp->command_block, 4838c2ecf20Sopenharmony_ci esp->command_block_dma); 4848c2ecf20Sopenharmony_cifail_unmap_regs: 4858c2ecf20Sopenharmony_ci pci_iounmap(pdev, esp->regs); 4868c2ecf20Sopenharmony_cifail_release_regions: 4878c2ecf20Sopenharmony_ci pci_release_regions(pdev); 4888c2ecf20Sopenharmony_cifail_priv_alloc: 4898c2ecf20Sopenharmony_ci kfree(pep); 4908c2ecf20Sopenharmony_cifail_host_alloc: 4918c2ecf20Sopenharmony_ci scsi_host_put(shost); 4928c2ecf20Sopenharmony_cifail_disable_device: 4938c2ecf20Sopenharmony_ci pci_disable_device(pdev); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return err; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic void pci_esp_remove_one(struct pci_dev *pdev) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci struct pci_esp_priv *pep = pci_get_drvdata(pdev); 5018c2ecf20Sopenharmony_ci struct esp *esp = pep->esp; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci scsi_esp_unregister(esp); 5048c2ecf20Sopenharmony_ci free_irq(pdev->irq, esp); 5058c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 5068c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, 16, esp->command_block, 5078c2ecf20Sopenharmony_ci esp->command_block_dma); 5088c2ecf20Sopenharmony_ci pci_iounmap(pdev, esp->regs); 5098c2ecf20Sopenharmony_ci pci_release_regions(pdev); 5108c2ecf20Sopenharmony_ci pci_disable_device(pdev); 5118c2ecf20Sopenharmony_ci kfree(pep); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci scsi_host_put(esp->host); 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic struct pci_device_id am53c974_pci_tbl[] = { 5178c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SCSI, 5188c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 5198c2ecf20Sopenharmony_ci { } 5208c2ecf20Sopenharmony_ci}; 5218c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, am53c974_pci_tbl); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic struct pci_driver am53c974_driver = { 5248c2ecf20Sopenharmony_ci .name = DRV_MODULE_NAME, 5258c2ecf20Sopenharmony_ci .id_table = am53c974_pci_tbl, 5268c2ecf20Sopenharmony_ci .probe = pci_esp_probe_one, 5278c2ecf20Sopenharmony_ci .remove = pci_esp_remove_one, 5288c2ecf20Sopenharmony_ci}; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cimodule_pci_driver(am53c974_driver); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AM53C974 SCSI driver"); 5338c2ecf20Sopenharmony_ciMODULE_AUTHOR("Hannes Reinecke <hare@suse.de>"); 5348c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 5358c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_MODULE_VERSION); 5368c2ecf20Sopenharmony_ciMODULE_ALIAS("tmscsim"); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cimodule_param(am53c974_debug, bool, 0644); 5398c2ecf20Sopenharmony_ciMODULE_PARM_DESC(am53c974_debug, "Enable debugging"); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cimodule_param(am53c974_fenab, bool, 0444); 5428c2ecf20Sopenharmony_ciMODULE_PARM_DESC(am53c974_fenab, "Enable 24-bit DMA transfer sizes"); 543