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