162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * AMD am53c974 driver. 462306a36Sopenharmony_ci * Copyright (c) 2014 Hannes Reinecke, SUSE Linux GmbH 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/pci.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <scsi/scsi_host.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "esp_scsi.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define DRV_MODULE_NAME "am53c974" 1962306a36Sopenharmony_ci#define DRV_MODULE_VERSION "1.00" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic bool am53c974_debug; 2262306a36Sopenharmony_cistatic bool am53c974_fenab = true; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define esp_dma_log(f, a...) \ 2562306a36Sopenharmony_ci do { \ 2662306a36Sopenharmony_ci if (am53c974_debug) \ 2762306a36Sopenharmony_ci shost_printk(KERN_DEBUG, esp->host, f, ##a); \ 2862306a36Sopenharmony_ci } while (0) 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define ESP_DMA_CMD 0x10 3162306a36Sopenharmony_ci#define ESP_DMA_STC 0x11 3262306a36Sopenharmony_ci#define ESP_DMA_SPA 0x12 3362306a36Sopenharmony_ci#define ESP_DMA_WBC 0x13 3462306a36Sopenharmony_ci#define ESP_DMA_WAC 0x14 3562306a36Sopenharmony_ci#define ESP_DMA_STATUS 0x15 3662306a36Sopenharmony_ci#define ESP_DMA_SMDLA 0x16 3762306a36Sopenharmony_ci#define ESP_DMA_WMAC 0x17 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define ESP_DMA_CMD_IDLE 0x00 4062306a36Sopenharmony_ci#define ESP_DMA_CMD_BLAST 0x01 4162306a36Sopenharmony_ci#define ESP_DMA_CMD_ABORT 0x02 4262306a36Sopenharmony_ci#define ESP_DMA_CMD_START 0x03 4362306a36Sopenharmony_ci#define ESP_DMA_CMD_MASK 0x03 4462306a36Sopenharmony_ci#define ESP_DMA_CMD_DIAG 0x04 4562306a36Sopenharmony_ci#define ESP_DMA_CMD_MDL 0x10 4662306a36Sopenharmony_ci#define ESP_DMA_CMD_INTE_P 0x20 4762306a36Sopenharmony_ci#define ESP_DMA_CMD_INTE_D 0x40 4862306a36Sopenharmony_ci#define ESP_DMA_CMD_DIR 0x80 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define ESP_DMA_STAT_PWDN 0x01 5162306a36Sopenharmony_ci#define ESP_DMA_STAT_ERROR 0x02 5262306a36Sopenharmony_ci#define ESP_DMA_STAT_ABORT 0x04 5362306a36Sopenharmony_ci#define ESP_DMA_STAT_DONE 0x08 5462306a36Sopenharmony_ci#define ESP_DMA_STAT_SCSIINT 0x10 5562306a36Sopenharmony_ci#define ESP_DMA_STAT_BCMPLT 0x20 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* EEPROM is accessed with 16-bit values */ 5862306a36Sopenharmony_ci#define DC390_EEPROM_READ 0x80 5962306a36Sopenharmony_ci#define DC390_EEPROM_LEN 0x40 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * DC390 EEPROM 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * 8 * 4 bytes of per-device options 6562306a36Sopenharmony_ci * followed by HBA specific options 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* Per-device options */ 6962306a36Sopenharmony_ci#define DC390_EE_MODE1 0x00 7062306a36Sopenharmony_ci#define DC390_EE_SPEED 0x01 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* HBA-specific options */ 7362306a36Sopenharmony_ci#define DC390_EE_ADAPT_SCSI_ID 0x40 7462306a36Sopenharmony_ci#define DC390_EE_MODE2 0x41 7562306a36Sopenharmony_ci#define DC390_EE_DELAY 0x42 7662306a36Sopenharmony_ci#define DC390_EE_TAG_CMD_NUM 0x43 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define DC390_EE_MODE1_PARITY_CHK 0x01 7962306a36Sopenharmony_ci#define DC390_EE_MODE1_SYNC_NEGO 0x02 8062306a36Sopenharmony_ci#define DC390_EE_MODE1_EN_DISC 0x04 8162306a36Sopenharmony_ci#define DC390_EE_MODE1_SEND_START 0x08 8262306a36Sopenharmony_ci#define DC390_EE_MODE1_TCQ 0x10 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define DC390_EE_MODE2_MORE_2DRV 0x01 8562306a36Sopenharmony_ci#define DC390_EE_MODE2_GREATER_1G 0x02 8662306a36Sopenharmony_ci#define DC390_EE_MODE2_RST_SCSI_BUS 0x04 8762306a36Sopenharmony_ci#define DC390_EE_MODE2_ACTIVE_NEGATION 0x08 8862306a36Sopenharmony_ci#define DC390_EE_MODE2_NO_SEEK 0x10 8962306a36Sopenharmony_ci#define DC390_EE_MODE2_LUN_CHECK 0x20 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistruct pci_esp_priv { 9262306a36Sopenharmony_ci struct esp *esp; 9362306a36Sopenharmony_ci u8 dma_status; 9462306a36Sopenharmony_ci}; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void pci_esp_dma_drain(struct esp *esp); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic inline struct pci_esp_priv *pci_esp_get_priv(struct esp *esp) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci return dev_get_drvdata(esp->dev); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic void pci_esp_write8(struct esp *esp, u8 val, unsigned long reg) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci iowrite8(val, esp->regs + (reg * 4UL)); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic u8 pci_esp_read8(struct esp *esp, unsigned long reg) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci return ioread8(esp->regs + (reg * 4UL)); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic void pci_esp_write32(struct esp *esp, u32 val, unsigned long reg) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci return iowrite32(val, esp->regs + (reg * 4UL)); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic int pci_esp_irq_pending(struct esp *esp) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci struct pci_esp_priv *pep = pci_esp_get_priv(esp); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci pep->dma_status = pci_esp_read8(esp, ESP_DMA_STATUS); 12362306a36Sopenharmony_ci esp_dma_log("dma intr dreg[%02x]\n", pep->dma_status); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (pep->dma_status & (ESP_DMA_STAT_ERROR | 12662306a36Sopenharmony_ci ESP_DMA_STAT_ABORT | 12762306a36Sopenharmony_ci ESP_DMA_STAT_DONE | 12862306a36Sopenharmony_ci ESP_DMA_STAT_SCSIINT)) 12962306a36Sopenharmony_ci return 1; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci return 0; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic void pci_esp_reset_dma(struct esp *esp) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci /* Nothing to do ? */ 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic void pci_esp_dma_drain(struct esp *esp) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci u8 resid; 14262306a36Sopenharmony_ci int lim = 1000; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if ((esp->sreg & ESP_STAT_PMASK) == ESP_DOP || 14662306a36Sopenharmony_ci (esp->sreg & ESP_STAT_PMASK) == ESP_DIP) 14762306a36Sopenharmony_ci /* Data-In or Data-Out, nothing to be done */ 14862306a36Sopenharmony_ci return; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci while (--lim > 0) { 15162306a36Sopenharmony_ci resid = pci_esp_read8(esp, ESP_FFLAGS) & ESP_FF_FBYTES; 15262306a36Sopenharmony_ci if (resid <= 1) 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci cpu_relax(); 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* 15862306a36Sopenharmony_ci * When there is a residual BCMPLT will never be set 15962306a36Sopenharmony_ci * (obviously). But we still have to issue the BLAST 16062306a36Sopenharmony_ci * command, otherwise the data will not being transferred. 16162306a36Sopenharmony_ci * But we'll never know when the BLAST operation is 16262306a36Sopenharmony_ci * finished. So check for some time and give up eventually. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_ci lim = 1000; 16562306a36Sopenharmony_ci pci_esp_write8(esp, ESP_DMA_CMD_DIR | ESP_DMA_CMD_BLAST, ESP_DMA_CMD); 16662306a36Sopenharmony_ci while (pci_esp_read8(esp, ESP_DMA_STATUS) & ESP_DMA_STAT_BCMPLT) { 16762306a36Sopenharmony_ci if (--lim == 0) 16862306a36Sopenharmony_ci break; 16962306a36Sopenharmony_ci cpu_relax(); 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci pci_esp_write8(esp, ESP_DMA_CMD_DIR | ESP_DMA_CMD_IDLE, ESP_DMA_CMD); 17262306a36Sopenharmony_ci esp_dma_log("DMA blast done (%d tries, %d bytes left)\n", lim, resid); 17362306a36Sopenharmony_ci /* BLAST residual handling is currently untested */ 17462306a36Sopenharmony_ci if (WARN_ON_ONCE(resid == 1)) { 17562306a36Sopenharmony_ci struct esp_cmd_entry *ent = esp->active_cmd; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci ent->flags |= ESP_CMD_FLAG_RESIDUAL; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic void pci_esp_dma_invalidate(struct esp *esp) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct pci_esp_priv *pep = pci_esp_get_priv(esp); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci esp_dma_log("invalidate DMA\n"); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci pci_esp_write8(esp, ESP_DMA_CMD_IDLE, ESP_DMA_CMD); 18862306a36Sopenharmony_ci pep->dma_status = 0; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic int pci_esp_dma_error(struct esp *esp) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct pci_esp_priv *pep = pci_esp_get_priv(esp); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (pep->dma_status & ESP_DMA_STAT_ERROR) { 19662306a36Sopenharmony_ci u8 dma_cmd = pci_esp_read8(esp, ESP_DMA_CMD); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if ((dma_cmd & ESP_DMA_CMD_MASK) == ESP_DMA_CMD_START) 19962306a36Sopenharmony_ci pci_esp_write8(esp, ESP_DMA_CMD_ABORT, ESP_DMA_CMD); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return 1; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci if (pep->dma_status & ESP_DMA_STAT_ABORT) { 20462306a36Sopenharmony_ci pci_esp_write8(esp, ESP_DMA_CMD_IDLE, ESP_DMA_CMD); 20562306a36Sopenharmony_ci pep->dma_status = pci_esp_read8(esp, ESP_DMA_CMD); 20662306a36Sopenharmony_ci return 1; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci return 0; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void pci_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, 21262306a36Sopenharmony_ci u32 dma_count, int write, u8 cmd) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct pci_esp_priv *pep = pci_esp_get_priv(esp); 21562306a36Sopenharmony_ci u32 val = 0; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci BUG_ON(!(cmd & ESP_CMD_DMA)); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci pep->dma_status = 0; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* Set DMA engine to IDLE */ 22262306a36Sopenharmony_ci if (write) 22362306a36Sopenharmony_ci /* DMA write direction logic is inverted */ 22462306a36Sopenharmony_ci val |= ESP_DMA_CMD_DIR; 22562306a36Sopenharmony_ci pci_esp_write8(esp, ESP_DMA_CMD_IDLE | val, ESP_DMA_CMD); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci pci_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); 22862306a36Sopenharmony_ci pci_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); 22962306a36Sopenharmony_ci if (esp->config2 & ESP_CONFIG2_FENAB) 23062306a36Sopenharmony_ci pci_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci pci_esp_write32(esp, esp_count, ESP_DMA_STC); 23362306a36Sopenharmony_ci pci_esp_write32(esp, addr, ESP_DMA_SPA); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci esp_dma_log("start dma addr[%x] count[%d:%d]\n", 23662306a36Sopenharmony_ci addr, esp_count, dma_count); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci scsi_esp_cmd(esp, cmd); 23962306a36Sopenharmony_ci /* Send DMA Start command */ 24062306a36Sopenharmony_ci pci_esp_write8(esp, ESP_DMA_CMD_START | val, ESP_DMA_CMD); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic u32 pci_esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci int dma_limit = 16; 24662306a36Sopenharmony_ci u32 base, end; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* 24962306a36Sopenharmony_ci * If CONFIG2_FENAB is set we can 25062306a36Sopenharmony_ci * handle up to 24 bit addresses 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_ci if (esp->config2 & ESP_CONFIG2_FENAB) 25362306a36Sopenharmony_ci dma_limit = 24; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (dma_len > (1U << dma_limit)) 25662306a36Sopenharmony_ci dma_len = (1U << dma_limit); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* 25962306a36Sopenharmony_ci * Prevent crossing a 24-bit address boundary. 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_ci base = dma_addr & ((1U << 24) - 1U); 26262306a36Sopenharmony_ci end = base + dma_len; 26362306a36Sopenharmony_ci if (end > (1U << 24)) 26462306a36Sopenharmony_ci end = (1U <<24); 26562306a36Sopenharmony_ci dma_len = end - base; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci return dma_len; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic const struct esp_driver_ops pci_esp_ops = { 27162306a36Sopenharmony_ci .esp_write8 = pci_esp_write8, 27262306a36Sopenharmony_ci .esp_read8 = pci_esp_read8, 27362306a36Sopenharmony_ci .irq_pending = pci_esp_irq_pending, 27462306a36Sopenharmony_ci .reset_dma = pci_esp_reset_dma, 27562306a36Sopenharmony_ci .dma_drain = pci_esp_dma_drain, 27662306a36Sopenharmony_ci .dma_invalidate = pci_esp_dma_invalidate, 27762306a36Sopenharmony_ci .send_dma_cmd = pci_esp_send_dma_cmd, 27862306a36Sopenharmony_ci .dma_error = pci_esp_dma_error, 27962306a36Sopenharmony_ci .dma_length_limit = pci_esp_dma_length_limit, 28062306a36Sopenharmony_ci}; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/* 28362306a36Sopenharmony_ci * Read DC-390 eeprom 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_cistatic void dc390_eeprom_prepare_read(struct pci_dev *pdev, u8 cmd) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci u8 carry_flag = 1, j = 0x80, bval; 28862306a36Sopenharmony_ci int i; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci for (i = 0; i < 9; i++) { 29162306a36Sopenharmony_ci if (carry_flag) { 29262306a36Sopenharmony_ci pci_write_config_byte(pdev, 0x80, 0x40); 29362306a36Sopenharmony_ci bval = 0xc0; 29462306a36Sopenharmony_ci } else 29562306a36Sopenharmony_ci bval = 0x80; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci udelay(160); 29862306a36Sopenharmony_ci pci_write_config_byte(pdev, 0x80, bval); 29962306a36Sopenharmony_ci udelay(160); 30062306a36Sopenharmony_ci pci_write_config_byte(pdev, 0x80, 0); 30162306a36Sopenharmony_ci udelay(160); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci carry_flag = (cmd & j) ? 1 : 0; 30462306a36Sopenharmony_ci j >>= 1; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic u16 dc390_eeprom_get_data(struct pci_dev *pdev) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci int i; 31162306a36Sopenharmony_ci u16 wval = 0; 31262306a36Sopenharmony_ci u8 bval; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci for (i = 0; i < 16; i++) { 31562306a36Sopenharmony_ci wval <<= 1; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci pci_write_config_byte(pdev, 0x80, 0x80); 31862306a36Sopenharmony_ci udelay(160); 31962306a36Sopenharmony_ci pci_write_config_byte(pdev, 0x80, 0x40); 32062306a36Sopenharmony_ci udelay(160); 32162306a36Sopenharmony_ci pci_read_config_byte(pdev, 0x00, &bval); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (bval == 0x22) 32462306a36Sopenharmony_ci wval |= 1; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci return wval; 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic void dc390_read_eeprom(struct pci_dev *pdev, u16 *ptr) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci u8 cmd = DC390_EEPROM_READ, i; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci for (i = 0; i < DC390_EEPROM_LEN; i++) { 33562306a36Sopenharmony_ci pci_write_config_byte(pdev, 0xc0, 0); 33662306a36Sopenharmony_ci udelay(160); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci dc390_eeprom_prepare_read(pdev, cmd++); 33962306a36Sopenharmony_ci *ptr++ = dc390_eeprom_get_data(pdev); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci pci_write_config_byte(pdev, 0x80, 0); 34262306a36Sopenharmony_ci pci_write_config_byte(pdev, 0x80, 0); 34362306a36Sopenharmony_ci udelay(160); 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic void dc390_check_eeprom(struct esp *esp) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(esp->dev); 35062306a36Sopenharmony_ci u8 EEbuf[128]; 35162306a36Sopenharmony_ci u16 *ptr = (u16 *)EEbuf, wval = 0; 35262306a36Sopenharmony_ci int i; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci dc390_read_eeprom(pdev, ptr); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci for (i = 0; i < DC390_EEPROM_LEN; i++, ptr++) 35762306a36Sopenharmony_ci wval += *ptr; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci /* no Tekram EEprom found */ 36062306a36Sopenharmony_ci if (wval != 0x1234) { 36162306a36Sopenharmony_ci dev_printk(KERN_INFO, &pdev->dev, 36262306a36Sopenharmony_ci "No valid Tekram EEprom found\n"); 36362306a36Sopenharmony_ci return; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci esp->scsi_id = EEbuf[DC390_EE_ADAPT_SCSI_ID]; 36662306a36Sopenharmony_ci esp->num_tags = 2 << EEbuf[DC390_EE_TAG_CMD_NUM]; 36762306a36Sopenharmony_ci if (EEbuf[DC390_EE_MODE2] & DC390_EE_MODE2_ACTIVE_NEGATION) 36862306a36Sopenharmony_ci esp->config4 |= ESP_CONFIG4_RADE | ESP_CONFIG4_RAE; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic int pci_esp_probe_one(struct pci_dev *pdev, 37262306a36Sopenharmony_ci const struct pci_device_id *id) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci const struct scsi_host_template *hostt = &scsi_esp_template; 37562306a36Sopenharmony_ci int err = -ENODEV; 37662306a36Sopenharmony_ci struct Scsi_Host *shost; 37762306a36Sopenharmony_ci struct esp *esp; 37862306a36Sopenharmony_ci struct pci_esp_priv *pep; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (pci_enable_device(pdev)) { 38162306a36Sopenharmony_ci dev_printk(KERN_INFO, &pdev->dev, "cannot enable device\n"); 38262306a36Sopenharmony_ci return -ENODEV; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { 38662306a36Sopenharmony_ci dev_printk(KERN_INFO, &pdev->dev, 38762306a36Sopenharmony_ci "failed to set 32bit DMA mask\n"); 38862306a36Sopenharmony_ci goto fail_disable_device; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci shost = scsi_host_alloc(hostt, sizeof(struct esp)); 39262306a36Sopenharmony_ci if (!shost) { 39362306a36Sopenharmony_ci dev_printk(KERN_INFO, &pdev->dev, 39462306a36Sopenharmony_ci "failed to allocate scsi host\n"); 39562306a36Sopenharmony_ci err = -ENOMEM; 39662306a36Sopenharmony_ci goto fail_disable_device; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci pep = kzalloc(sizeof(struct pci_esp_priv), GFP_KERNEL); 40062306a36Sopenharmony_ci if (!pep) { 40162306a36Sopenharmony_ci dev_printk(KERN_INFO, &pdev->dev, 40262306a36Sopenharmony_ci "failed to allocate esp_priv\n"); 40362306a36Sopenharmony_ci err = -ENOMEM; 40462306a36Sopenharmony_ci goto fail_host_alloc; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci esp = shost_priv(shost); 40862306a36Sopenharmony_ci esp->host = shost; 40962306a36Sopenharmony_ci esp->dev = &pdev->dev; 41062306a36Sopenharmony_ci esp->ops = &pci_esp_ops; 41162306a36Sopenharmony_ci /* 41262306a36Sopenharmony_ci * The am53c974 HBA has a design flaw of generating 41362306a36Sopenharmony_ci * spurious DMA completion interrupts when using 41462306a36Sopenharmony_ci * DMA for command submission. 41562306a36Sopenharmony_ci */ 41662306a36Sopenharmony_ci esp->flags |= ESP_FLAG_USE_FIFO; 41762306a36Sopenharmony_ci /* 41862306a36Sopenharmony_ci * Enable CONFIG2_FENAB to allow for large DMA transfers 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_ci if (am53c974_fenab) 42162306a36Sopenharmony_ci esp->config2 |= ESP_CONFIG2_FENAB; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci pep->esp = esp; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (pci_request_regions(pdev, DRV_MODULE_NAME)) { 42662306a36Sopenharmony_ci dev_printk(KERN_ERR, &pdev->dev, 42762306a36Sopenharmony_ci "pci memory selection failed\n"); 42862306a36Sopenharmony_ci goto fail_priv_alloc; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci esp->regs = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); 43262306a36Sopenharmony_ci if (!esp->regs) { 43362306a36Sopenharmony_ci dev_printk(KERN_ERR, &pdev->dev, "pci I/O map failed\n"); 43462306a36Sopenharmony_ci err = -EINVAL; 43562306a36Sopenharmony_ci goto fail_release_regions; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci esp->dma_regs = esp->regs; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci pci_set_master(pdev); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci esp->command_block = dma_alloc_coherent(&pdev->dev, 16, 44262306a36Sopenharmony_ci &esp->command_block_dma, GFP_KERNEL); 44362306a36Sopenharmony_ci if (!esp->command_block) { 44462306a36Sopenharmony_ci dev_printk(KERN_ERR, &pdev->dev, 44562306a36Sopenharmony_ci "failed to allocate command block\n"); 44662306a36Sopenharmony_ci err = -ENOMEM; 44762306a36Sopenharmony_ci goto fail_unmap_regs; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci pci_set_drvdata(pdev, pep); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci err = request_irq(pdev->irq, scsi_esp_intr, IRQF_SHARED, 45362306a36Sopenharmony_ci DRV_MODULE_NAME, esp); 45462306a36Sopenharmony_ci if (err < 0) { 45562306a36Sopenharmony_ci dev_printk(KERN_ERR, &pdev->dev, "failed to register IRQ\n"); 45662306a36Sopenharmony_ci goto fail_unmap_command_block; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci esp->scsi_id = 7; 46062306a36Sopenharmony_ci dc390_check_eeprom(esp); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci shost->this_id = esp->scsi_id; 46362306a36Sopenharmony_ci shost->max_id = 8; 46462306a36Sopenharmony_ci shost->irq = pdev->irq; 46562306a36Sopenharmony_ci shost->io_port = pci_resource_start(pdev, 0); 46662306a36Sopenharmony_ci shost->n_io_port = pci_resource_len(pdev, 0); 46762306a36Sopenharmony_ci shost->unique_id = shost->io_port; 46862306a36Sopenharmony_ci esp->scsi_id_mask = (1 << esp->scsi_id); 46962306a36Sopenharmony_ci /* Assume 40MHz clock */ 47062306a36Sopenharmony_ci esp->cfreq = 40000000; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci err = scsi_esp_register(esp); 47362306a36Sopenharmony_ci if (err) 47462306a36Sopenharmony_ci goto fail_free_irq; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return 0; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cifail_free_irq: 47962306a36Sopenharmony_ci free_irq(pdev->irq, esp); 48062306a36Sopenharmony_cifail_unmap_command_block: 48162306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 48262306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, 16, esp->command_block, 48362306a36Sopenharmony_ci esp->command_block_dma); 48462306a36Sopenharmony_cifail_unmap_regs: 48562306a36Sopenharmony_ci pci_iounmap(pdev, esp->regs); 48662306a36Sopenharmony_cifail_release_regions: 48762306a36Sopenharmony_ci pci_release_regions(pdev); 48862306a36Sopenharmony_cifail_priv_alloc: 48962306a36Sopenharmony_ci kfree(pep); 49062306a36Sopenharmony_cifail_host_alloc: 49162306a36Sopenharmony_ci scsi_host_put(shost); 49262306a36Sopenharmony_cifail_disable_device: 49362306a36Sopenharmony_ci pci_disable_device(pdev); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci return err; 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic void pci_esp_remove_one(struct pci_dev *pdev) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci struct pci_esp_priv *pep = pci_get_drvdata(pdev); 50162306a36Sopenharmony_ci struct esp *esp = pep->esp; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci scsi_esp_unregister(esp); 50462306a36Sopenharmony_ci free_irq(pdev->irq, esp); 50562306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 50662306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, 16, esp->command_block, 50762306a36Sopenharmony_ci esp->command_block_dma); 50862306a36Sopenharmony_ci pci_iounmap(pdev, esp->regs); 50962306a36Sopenharmony_ci pci_release_regions(pdev); 51062306a36Sopenharmony_ci pci_disable_device(pdev); 51162306a36Sopenharmony_ci kfree(pep); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci scsi_host_put(esp->host); 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic struct pci_device_id am53c974_pci_tbl[] = { 51762306a36Sopenharmony_ci { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SCSI, 51862306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 51962306a36Sopenharmony_ci { } 52062306a36Sopenharmony_ci}; 52162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, am53c974_pci_tbl); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic struct pci_driver am53c974_driver = { 52462306a36Sopenharmony_ci .name = DRV_MODULE_NAME, 52562306a36Sopenharmony_ci .id_table = am53c974_pci_tbl, 52662306a36Sopenharmony_ci .probe = pci_esp_probe_one, 52762306a36Sopenharmony_ci .remove = pci_esp_remove_one, 52862306a36Sopenharmony_ci}; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cimodule_pci_driver(am53c974_driver); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ciMODULE_DESCRIPTION("AM53C974 SCSI driver"); 53362306a36Sopenharmony_ciMODULE_AUTHOR("Hannes Reinecke <hare@suse.de>"); 53462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 53562306a36Sopenharmony_ciMODULE_VERSION(DRV_MODULE_VERSION); 53662306a36Sopenharmony_ciMODULE_ALIAS("tmscsim"); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cimodule_param(am53c974_debug, bool, 0644); 53962306a36Sopenharmony_ciMODULE_PARM_DESC(am53c974_debug, "Enable debugging"); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cimodule_param(am53c974_fenab, bool, 0444); 54262306a36Sopenharmony_ciMODULE_PARM_DESC(am53c974_fenab, "Enable 24-bit DMA transfer sizes"); 543