patch-2.4.22 linux-2.4.22/drivers/ide/pci/siimage.c

Next file: linux-2.4.22/drivers/ide/pci/siimage.h
Previous file: linux-2.4.22/drivers/ide/pci/pdc202xx_old.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.21/drivers/ide/pci/siimage.c linux-2.4.22/drivers/ide/pci/siimage.c
@@ -1,10 +1,24 @@
 /*
- * linux/drivers/ide/pci/siimage.c		Version 1.02	Jan 30, 2003
+ * linux/drivers/ide/pci/siimage.c		Version 1.06	June 11, 2003
  *
  * Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org>
  * Copyright (C) 2003		Red Hat <alan@redhat.com>
  *
  *  May be copied or modified under the terms of the GNU General Public License
+ *
+ *  Documentation available under NDA only
+ *
+ *
+ *  FAQ Items:
+ *	If you are using Marvell SATA-IDE adapters with Maxtor drives
+ *	ensure the system is set up for ATA100/UDMA5 not UDMA6.
+ *
+ *	If you are using WD drives with SATA bridges you must set the
+ *	drive to "Single". "Master" will hang
+ *
+ *	If you have strange problems with nVidia chipset systems please
+ *	see the SI support documentation and update your system BIOS
+ *	if neccessary
  */
 
 #include <linux/config.h>
@@ -30,12 +44,102 @@
 static struct pci_dev *siimage_devs[SIIMAGE_MAX_DEVS];
 static int n_siimage_devs;
 
-static char * print_siimage_get_info (char *buf, struct pci_dev *dev, int index)
+/**
+ *	pdev_is_sata		-	check if device is SATA
+ *	@pdev:	PCI device to check
+ *	
+ *	Returns true if this is a SATA controller
+ */
+ 
+static int pdev_is_sata(struct pci_dev *pdev)
+{
+	switch(pdev->device)
+	{
+		case PCI_DEVICE_ID_SII_3112:
+		case PCI_DEVICE_ID_SII_1210SA:
+			return 1;
+		case PCI_DEVICE_ID_SII_680:
+			return 0;
+	}
+	BUG();
+}
+ 
+/**
+ *	is_sata			-	check if hwif is SATA
+ *	@hwif:	interface to check
+ *	
+ *	Returns true if this is a SATA controller
+ */
+ 
+static inline int is_sata(ide_hwif_t *hwif)
+{
+	return pdev_is_sata(hwif->pci_dev);
+}
+
+/**
+ *	siimage_selreg		-	return register base
+ *	@hwif: interface
+ *	@r: config offset
+ *
+ *	Turn a config register offset into the right address in either
+ *	PCI space or MMIO space to access the control register in question
+ *	Thankfully this is a configuration operation so isnt performance
+ *	criticial. 
+ */
+ 
+static unsigned long siimage_selreg(ide_hwif_t *hwif, int r)
+{
+	unsigned long base = (unsigned long)hwif->hwif_data;
+	base += 0xA0 + r;
+	if(hwif->mmio)
+		base += (hwif->channel << 6);
+	else
+		base += (hwif->channel << 4);
+	return base;
+}
+	
+/**
+ *	siimage_seldev		-	return register base
+ *	@hwif: interface
+ *	@r: config offset
+ *
+ *	Turn a config register offset into the right address in either
+ *	PCI space or MMIO space to access the control register in question
+ *	including accounting for the unit shift.
+ */
+ 
+static inline unsigned long siimage_seldev(ide_drive_t *drive, int r)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long base = (unsigned long)hwif->hwif_data;
+	base += 0xA0 + r;
+	if(hwif->mmio)
+		base += (hwif->channel << 6);
+	else
+		base += (hwif->channel << 4);
+	base |= drive->select.b.unit << drive->select.b.unit;
+	return base;
+}
+	
+/**
+ *	print_siimage_get_info	-	print minimal proc information
+ *	@buf: buffer to write into (kernel space)
+ *	@dev: PCI device we are describing
+ *	@index: Controller number
+ *
+ *	Print the basic information for the state of the CMD680/SI3112
+ *	channel. We don't actually dump a lot of information out for
+ *	this controller although we could expand it if we needed.
+ */
+ 
+static char *print_siimage_get_info (char *buf, struct pci_dev *dev, int index)
 {
 	char *p		= buf;
 	u8 mmio		= (pci_get_drvdata(dev) != NULL) ? 1 : 0;
-	unsigned long bmdma	= (mmio) ? ((unsigned long) pci_get_drvdata(dev)) :
-				    (pci_resource_start(dev, 4));
+	unsigned long bmdma = pci_resource_start(dev, 4);
+	
+	if(mmio)
+		bmdma = pci_resource_start(dev, 5);
 
 	p += sprintf(p, "\nController: %d\n", index);
 	p += sprintf(p, "SiI%x Chipset.\n", dev->device);
@@ -43,18 +147,20 @@
 		p += sprintf(p, "MMIO Base 0x%lx\n", bmdma);
 	p += sprintf(p, "%s-DMA Base 0x%lx\n", (mmio)?"MMIO":"BM", bmdma);
 	p += sprintf(p, "%s-DMA Base 0x%lx\n", (mmio)?"MMIO":"BM", bmdma+8);
-
-	p += sprintf(p, "--------------- Primary Channel "
-			"---------------- Secondary Channel "
-			"-------------\n");
-	p += sprintf(p, "--------------- drive0 --------- drive1 "
-			"-------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "PIO Mode:       %s                %s"
-			"               %s                 %s\n",
-			"?", "?", "?", "?");
 	return (char *)p;
 }
 
+/**
+ *	siimage_get_info	-	proc callback
+ *	@buffer: kernel buffer to complete
+ *	@addr: written with base of data to return
+ *	offset: seek offset
+ *	count: bytes to fill in 
+ *
+ *	Called when the user reads data from the virtual file for this
+ *	controller from /proc
+ */
+ 
 static int siimage_get_info (char *buffer, char **addr, off_t offset, int count)
 {
 	char *p = buffer;
@@ -89,44 +195,56 @@
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	u8 mode	= 0, scsc = 0;
+	unsigned long base = (unsigned long) hwif->hwif_data;
 
 	if (hwif->mmio)
-		scsc = hwif->INB(HWIFADDR(0x4A));
+		scsc = hwif->INB(base + 0x4A);
 	else
 		pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
 
-	switch(hwif->pci_dev->device) {
-		case PCI_DEVICE_ID_SII_3112:
-			return 4;
-		case PCI_DEVICE_ID_SII_680:
-			if ((scsc & 0x30) == 0x10)	/* 133 */
-				mode = 4;
-			else if ((scsc & 0x30) == 0x20)	/* 2xPCI */
-				mode = 4;
-			else if ((scsc & 0x30) == 0x00)	/* 100 */
-				mode = 3;
-			else 	/* Disabled ? */
-				BUG();
-			break;
-		default:	return 0;
+	if(is_sata(hwif))
+	{
+		if(strstr(drive->id->model, "Maxtor"))
+			return 3;
+		return 4;
 	}
+	
+	if ((scsc & 0x30) == 0x10)	/* 133 */
+		mode = 4;
+	else if ((scsc & 0x30) == 0x20)	/* 2xPCI */
+		mode = 4;
+	else if ((scsc & 0x30) == 0x00)	/* 100 */
+		mode = 3;
+	else 	/* Disabled ? */
+		BUG();
+
 	if (!eighty_ninty_three(drive))
 		mode = min(mode, (u8)1);
 	return mode;
 }
 
+/**
+ *	siimage_taskfile_timing	-	turn timing data to a mode
+ *	@hwif: interface to query
+ *
+ *	Read the timing data for the interface and return the 
+ *	mode that is being used.
+ */
+ 
 static byte siimage_taskfile_timing (ide_hwif_t *hwif)
 {
 	u16 timing	= 0x328a;
+	unsigned long addr = siimage_selreg(hwif, 2);
 
 	if (hwif->mmio)
-		timing = hwif->INW(SELADDR(2));
+		timing = hwif->INW(addr);
 	else
-		pci_read_config_word(hwif->pci_dev, SELREG(2), &timing);
+		pci_read_config_word(hwif->pci_dev, addr, &timing);
 
 	switch (timing) {
 		case 0x10c1:	return 4;
 		case 0x10c3:	return 3;
+		case 0x1104:
 		case 0x1281:	return 2;
 		case 0x2283:	return 1;
 		case 0x328a:
@@ -140,37 +258,82 @@
  *	@mode_wanted: the target operating mode
  *
  *	Load the timing settings for this device mode into the
- *	controller
+ *	controller. If we are in PIO mode 3 or 4 turn on IORDY
+ *	monitoring (bit 9). The TF timing is bits 31:16
  */
  
 static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	u16 speedt		= 0;
-	u8 unit			= drive->select.b.unit;
-
-	if (hwif->mmio)
-		speedt = hwif->INW(SELADDR(0x04|(unit<<unit)));
-	else
-		pci_read_config_word(dev, SELADDR(0x04|(unit<<unit)), &speedt);
-
+	u32 speedt		= 0;
+	u16 speedp		= 0;
+	unsigned long addr	= siimage_seldev(drive, 0x04);
+	unsigned long tfaddr	= siimage_selreg(hwif, 0x02);
+	
 	/* cheat for now and use the docs */
-//	switch(siimage_taskfile_timing(hwif)) {
 	switch(mode_wanted) {
-		case 4:		speedt = 0x10c1; break;
-		case 3:		speedt = 0x10C3; break;
-		case 2:		speedt = 0x1104; break;
-		case 1:		speedt = 0x2283; break;
+		case 4:	
+			speedp = 0x10c1; 
+			speedt = 0x10c1;
+			break;
+		case 3:	
+			speedp = 0x10C3; 
+			speedt = 0x10C3;
+			break;
+		case 2:	
+			speedp = 0x1104; 
+			speedt = 0x1281;
+			break;
+		case 1:		
+			speedp = 0x2283; 
+			speedt = 0x1281;
+			break;
 		case 0:
-		default:	speedt = 0x328A; break;
+		default:
+			speedp = 0x328A; 
+			speedt = 0x328A;
+			break;
 	}
 	if (hwif->mmio)
-		hwif->OUTW(speedt, SELADDR(0x04|(unit<<unit)));
+	{
+		hwif->OUTW(speedt, addr);
+		hwif->OUTW(speedp, tfaddr);
+		/* Now set up IORDY */
+		if(mode_wanted == 3 || mode_wanted == 4)
+			hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2);
+		else
+			hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2);
+	}
 	else
-		pci_write_config_word(dev, SELADDR(0x04|(unit<<unit)), speedt);
+	{
+		pci_write_config_word(hwif->pci_dev, addr, speedp);
+		pci_write_config_word(hwif->pci_dev, tfaddr, speedt);
+		pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp);
+		speedp &= ~0x200;
+		/* Set IORDY for mode 3 or 4 */
+		if(mode_wanted == 3 || mode_wanted == 4)
+			speedp |= 0x200;
+		pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp);
+	}
 }
 
+/**
+ *	config_siimage_chipset_for_pio	-	set drive timings
+ *	@drive: drive to tune
+ *	@speed we want
+ *
+ *	Compute the best pio mode we can for a given device. Also honour
+ *	the timings for the driver when dealing with mixed devices. Some
+ *	of this is ugly but its all wrapped up here
+ *
+ *	The SI680 can also do VDMA - we need to start using that
+ *
+ *	FIXME: we use the BIOS channel timings to avoid driving the task
+ *	files too fast at the disk. We need to compute the master/slave
+ *	drive PIO mode properly so that we can up the speed on a hotplug
+ *	system.
+ */
+ 
 static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed)
 {
 	u8 channel_timings	= siimage_taskfile_timing(HWIF(drive));
@@ -191,6 +354,16 @@
 	config_siimage_chipset_for_pio(drive, set_speed);
 }
 
+/**
+ *	siimage_tune_chipset	-	set controller timings
+ *	@drive: Drive to set up
+ *	@xferspeed: speed we want to achieve
+ *
+ *	Tune the SII chipset for the desired mode. If we can't achieve
+ *	the desired mode then tune for a lower one, but ultimately
+ *	make the thing work.
+ */
+ 
 static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
 {
 	u8 ultra6[]		= { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
@@ -200,30 +373,32 @@
 	ide_hwif_t *hwif	= HWIF(drive);
 	u16 ultra = 0, multi	= 0;
 	u8 mode = 0, unit	= drive->select.b.unit;
-	u8 speed	= ide_rate_filter(siimage_ratemask(drive), xferspeed);
+	u8 speed		= ide_rate_filter(siimage_ratemask(drive), xferspeed);
+	unsigned long base	= (unsigned long)hwif->hwif_data;
 	u8 scsc = 0, addr_mask	= ((hwif->channel) ?
 				    ((hwif->mmio) ? 0xF4 : 0x84) :
 				    ((hwif->mmio) ? 0xB4 : 0x80));
+				    
+	unsigned long ma	= siimage_seldev(drive, 0x08);
+	unsigned long ua	= siimage_seldev(drive, 0x0C);
 
 	if (hwif->mmio) {
-		scsc = hwif->INB(HWIFADDR(0x4A));
-		mode = hwif->INB(HWIFADDR(addr_mask));
-		multi = hwif->INW(SELADDR(0x08|(unit<<unit)));
-		ultra = hwif->INW(SELADDR(0x0C|(unit<<unit)));
+		scsc = hwif->INB(base + 0x4A);
+		mode = hwif->INB(base + addr_mask);
+		multi = hwif->INW(ma);
+		ultra = hwif->INW(ua);
 	} else {
 		pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
 		pci_read_config_byte(hwif->pci_dev, addr_mask, &mode);
-		pci_read_config_word(hwif->pci_dev,
-				SELREG(0x08|(unit<<unit)), &multi);
-		pci_read_config_word(hwif->pci_dev,
-				SELREG(0x0C|(unit<<unit)), &ultra);
+		pci_read_config_word(hwif->pci_dev, ma, &multi);
+		pci_read_config_word(hwif->pci_dev, ua, &ultra);
 	}
 
 	mode &= ~((unit) ? 0x30 : 0x03);
 	ultra &= ~0x3F;
 	scsc = ((scsc & 0x30) == 0x00) ? 0 : 1;
 
-	scsc = (hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112) ? 1 : scsc;
+	scsc = is_sata(hwif) ? 1 : scsc;
 
 	switch(speed) {
 		case XFER_PIO_4:
@@ -259,20 +434,26 @@
 	}
 
 	if (hwif->mmio) {
-		hwif->OUTB(mode, HWIFADDR(addr_mask));
-		hwif->OUTW(multi, SELADDR(0x08|(unit<<unit)));
-		hwif->OUTW(ultra, SELADDR(0x0C|(unit<<unit)));
+		hwif->OUTB(mode, base + addr_mask);
+		hwif->OUTW(multi, ma);
+		hwif->OUTW(ultra, ua);
 	} else {
 		pci_write_config_byte(hwif->pci_dev, addr_mask, mode);
-		pci_write_config_word(hwif->pci_dev,
-				SELREG(0x08|(unit<<unit)), multi);
-		pci_write_config_word(hwif->pci_dev,
-				SELREG(0x0C|(unit<<unit)), ultra);
+		pci_write_config_word(hwif->pci_dev, ma, multi);
+		pci_write_config_word(hwif->pci_dev, ua, ultra);
 	}
-
 	return (ide_config_drive_speed(drive, speed));
 }
 
+/**
+ *	config_chipset_for_dma	-	configure for DMA
+ *	@drive: drive to configure
+ *
+ *	Called by the IDE layer when it wants the timings set up.
+ *	For the CMD680 we also need to set up the PIO timings and
+ *	enable DMA.
+ */
+ 
 static int config_chipset_for_dma (ide_drive_t *drive)
 {
 	u8 speed	= ide_dma_speed(drive, siimage_ratemask(drive));
@@ -291,14 +472,22 @@
 	return ide_dma_enable(drive);
 }
 
+/**
+ *	siimage_configure_drive_for_dma	-	set up for DMA transfers
+ *	@drive: drive we are going to set up
+ *
+ *	Set up the drive for DMA, tune the controller and drive as 
+ *	required. If the drive isn't suitable for DMA or we hit
+ *	other problems then we will drop down to PIO and set up
+ *	PIO appropriately
+ */
+ 
 static int siimage_config_drive_for_dma (ide_drive_t *drive)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct hd_driveid *id	= drive->id;
 
 	if ((id->capability & 1) != 0 && drive->autodma) {
-		if (!(hwif->atapi_dma))
-			goto fast_ata_pio;
 		/* Consult the list of known "bad" drives */
 		if (hwif->ide_dma_bad_drive(drive))
 			goto fast_ata_pio;
@@ -340,18 +529,28 @@
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	u8 dma_altstat		= 0;
+	unsigned long addr	= siimage_selreg(hwif, 1);
 
 	/* return 1 if INTR asserted */
 	if ((hwif->INB(hwif->dma_status) & 4) == 4)
 		return 1;
 
 	/* return 1 if Device INTR asserted */
-	pci_read_config_byte(hwif->pci_dev, SELREG(1), &dma_altstat);
+	pci_read_config_byte(hwif->pci_dev, addr, &dma_altstat);
 	if (dma_altstat & 8)
 		return 0;	//return 1;
 	return 0;
 }
 
+/**
+ *	siimage_mmio_ide_dma_count	-	DMA bytes done
+ *	@drive
+ *
+ *	If we are doing VDMA the CMD680 requires a little bit
+ *	of more careful handling and we have to read the counts
+ *	off ourselves. For non VDMA life is normal.
+ */
+ 
 static int siimage_mmio_ide_dma_count (ide_drive_t *drive)
 {
 #ifdef SIIMAGE_VIRTUAL_DMAPIO
@@ -359,9 +558,10 @@
 	ide_hwif_t *hwif	= HWIF(drive);
 	u32 count		= (rq->nr_sectors * SECTOR_SIZE);
 	u32 rcount		= 0;
+	unsigned long addr	= siimage_selreg(hwif, 0x1C);
 
-	hwif->OUTL(count, SELADDR(0x1C));
-	rcount = hwif->INL(SELADDR(0x1C));
+	hwif->OUTL(count, addr);
+	rcount = hwif->INL(addr);
 
 	printk("\n%s: count = %d, rcount = %d, nr_sectors = %lu\n",
 		drive->name, count, rcount, rq->nr_sectors);
@@ -370,13 +570,22 @@
 	return __ide_dma_count(drive);
 }
 
-/* returns 1 if dma irq issued, 0 otherwise */
+/**
+ *	siimage_mmio_ide_dma_test_irq	-	check we caused an IRQ
+ *	@drive: drive we are testing
+ *
+ *	Check if we caused an IDE DMA interrupt. We may also have caused
+ *	SATA status interrupts, if so we clean them up and continue.
+ */
+ 
 static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long base	= (unsigned long)hwif->hwif_data;
+	unsigned long addr	= siimage_selreg(hwif, 0x1);
 
 	if (SATA_ERROR_REG) {
-		u32 ext_stat = hwif->INL(HWIFADDR(0x10));
+		u32 ext_stat = hwif->INL(base + 0x10);
 		u8 watchdog = 0;
 		if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) {
 			u32 sata_error = hwif->INL(SATA_ERROR_REG);
@@ -403,7 +612,7 @@
 		return 1;
 
 	/* return 1 if Device INTR asserted */
-	if ((hwif->INB(SELADDR(1)) & 8) == 8)
+	if ((hwif->INB(addr) & 8) == 8)
 		return 0;	//return 1;
 
 	return 0;
@@ -412,9 +621,6 @@
 static int siimage_mmio_ide_dma_verbose (ide_drive_t *drive)
 {
 	int temp = __ide_dma_verbose(drive);
-#if 0
-	drive->using_dma = 0;
-#endif
 	return temp;
 }
 
@@ -432,11 +638,12 @@
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	u32 stat_config		= 0;
+	unsigned long addr	= siimage_selreg(hwif, 0);
 
 	if (hwif->mmio) {
-		stat_config = hwif->INL(SELADDR(0));
+		stat_config = hwif->INL(addr);
 	} else
-		pci_read_config_dword(hwif->pci_dev, SELREG(0), &stat_config);
+		pci_read_config_dword(hwif->pci_dev, addr, &stat_config);
 
 	switch (state) {
 		case BUSSTATE_ON:
@@ -458,6 +665,14 @@
 	return 0;
 }
 
+/**
+ *	siimage_reset_poll	-	wait for sata reset
+ *	@drive: drive we are resetting
+ *
+ *	Poll the SATA phy and see whether it has come back from the dead
+ *	yet.
+ */
+ 
 static int siimage_reset_poll (ide_drive_t *drive)
 {
 	if (SATA_STATUS_REG) {
@@ -488,7 +703,8 @@
 	if (drive->media != ide_disk)
 		return;
 
-	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_SII_3112) {
+	if (is_sata(HWIF(drive)))
+	{
 		drive->special.b.set_geometry = 0;
 		drive->special.b.recalibrate = 0;
 	}
@@ -506,19 +722,21 @@
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	u8 reset		= 0;
+	unsigned long addr	= siimage_selreg(hwif, 0);
 
 	if (hwif->mmio) {
-		reset = hwif->INB(SELADDR(0));
-		hwif->OUTB((reset|0x03), SELADDR(0));
+		reset = hwif->INB(addr);
+		hwif->OUTB((reset|0x03), addr);
+		/* FIXME:posting */
 		udelay(25);
-		hwif->OUTB(reset, SELADDR(0));
-		(void) hwif->INB(SELADDR(0));
+		hwif->OUTB(reset, addr);
+		(void) hwif->INB(addr);
 	} else {
-		pci_read_config_byte(hwif->pci_dev, SELREG(0), &reset);
-		pci_write_config_byte(hwif->pci_dev, SELREG(0), reset|0x03);
+		pci_read_config_byte(hwif->pci_dev, addr, &reset);
+		pci_write_config_byte(hwif->pci_dev, addr, reset|0x03);
 		udelay(25);
-		pci_write_config_byte(hwif->pci_dev, SELREG(0), reset);
-		pci_read_config_byte(hwif->pci_dev, SELREG(0), &reset);
+		pci_write_config_byte(hwif->pci_dev, addr, reset);
+		pci_read_config_byte(hwif->pci_dev, addr, &reset);
 	}
 
 	if (SATA_STATUS_REG) {
@@ -546,11 +764,11 @@
  
 static void proc_reports_siimage (struct pci_dev *dev, u8 clocking, const char *name)
 {
-	if (dev->device == PCI_DEVICE_ID_SII_3112)
+	if(pdev_is_sata(dev))
 		goto sata_skip;
 
 	printk(KERN_INFO "%s: BASE CLOCK ", name);
-	clocking &= ~0x03;
+	clocking &= 0x03;
 	switch(clocking) {
 		case 0x03: printk("DISABLED !\n"); break;
 		case 0x02: printk("== 2X PCI \n"); break;
@@ -570,10 +788,20 @@
 #endif /* DISPLAY_SIIMAGE_TIMINGS && CONFIG_PROC_FS */
 }
 
+/**
+ *	setup_mmio_siimage	-	switch an SI controller into MMIO
+ *	@dev: PCI device we are configuring
+ *	@name: device name
+ *
+ *	Attempt to put the device into mmio mode. There are some slight
+ *	complications here with certain systems where the mmio bar isnt
+ *	mapped so we have to be sure we can fall back to I/O.
+ */
+ 
 static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name)
 {
 	unsigned long bar5	= pci_resource_start(dev, 5);
-	unsigned long len5	= pci_resource_len(dev, 5);
+	unsigned long barsize	= pci_resource_len(dev, 5);
 	u8 tmpbyte	= 0;
 	unsigned long addr;
 	void *ioaddr;
@@ -584,34 +812,37 @@
 	 *	spaces.
 	 */
 	 
-	if(check_mem_region(bar5, len5)!=0)
+	if(!request_mem_region(bar5, barsize, name))
 	{
 		printk(KERN_WARNING "siimage: IDE controller MMIO ports not available.\n");
 		return 0;
 	}
 		
-	ioaddr = ioremap_nocache(bar5, len5);
+	ioaddr = ioremap(bar5, barsize);
 
 	if (ioaddr == NULL)
+	{
+		release_mem_region(bar5, barsize);
 		return 0;
+	}
 
 	pci_set_master(dev);
 	pci_set_drvdata(dev, ioaddr);
 	addr = (unsigned long) ioaddr;
 
-	if (dev->device == PCI_DEVICE_ID_SII_3112) {
-		writel(0, DEVADDR(0x148));
-		writel(0, DEVADDR(0x1C8));
+	if (pdev_is_sata(dev)) {
+		writel(0, addr + 0x148);
+		writel(0, addr + 0x1C8);
 	}
 
-	writeb(0, DEVADDR(0xB4));
-	writeb(0, DEVADDR(0xF4));
-	tmpbyte = readb(DEVADDR(0x4A));
+	writeb(0, addr + 0xB4);
+	writeb(0, addr + 0xF4);
+	tmpbyte = readb(addr + 0x4A);
 
 	switch(tmpbyte & 0x30) {
 		case 0x00:
 			/* In 100 MHz clocking, try and switch to 133 */
-			writeb(tmpbyte|0x10, DEVADDR(0x4A));
+			writeb(tmpbyte|0x10, addr + 0x4A);
 			break;
 		case 0x10:
 			/* On 133Mhz clocking */
@@ -622,34 +853,43 @@
 		case 0x30:
 			/* Clocking is disabled */
 			/* 133 clock attempt to force it on */
-			writeb(tmpbyte & ~0x20, DEVADDR(0x4A));
+			writeb(tmpbyte & ~0x20, addr + 0x4A);
 			break;
 	}
 	
-	writeb(0x72, DEVADDR(0xA1));
-	writew(0x328A, DEVADDR(0xA2));
-	writel(0x62DD62DD, DEVADDR(0xA4));
-	writel(0x43924392, DEVADDR(0xA8));
-	writel(0x40094009, DEVADDR(0xAC));
-	writeb(0x72, DEVADDR(0xE1));
-	writew(0x328A, DEVADDR(0xE2));
-	writel(0x62DD62DD, DEVADDR(0xE4));
-	writel(0x43924392, DEVADDR(0xE8));
-	writel(0x40094009, DEVADDR(0xEC));
-
-	if (dev->device == PCI_DEVICE_ID_SII_3112) {
-		writel(0xFFFF0000, DEVADDR(0x108));
-		writel(0xFFFF0000, DEVADDR(0x188));
-		writel(0x00680000, DEVADDR(0x148));
-		writel(0x00680000, DEVADDR(0x1C8));
+	writeb(      0x72, addr + 0xA1);
+	writew(    0x328A, addr + 0xA2);
+	writel(0x62DD62DD, addr + 0xA4);
+	writel(0x43924392, addr + 0xA8);
+	writel(0x40094009, addr + 0xAC);
+	writeb(      0x72, addr + 0xE1);
+	writew(    0x328A, addr + 0xE2);
+	writel(0x62DD62DD, addr + 0xE4);
+	writel(0x43924392, addr + 0xE8);
+	writel(0x40094009, addr + 0xEC);
+
+	if (pdev_is_sata(dev)) {
+		writel(0xFFFF0000, addr + 0x108);
+		writel(0xFFFF0000, addr + 0x188);
+		writel(0x00680000, addr + 0x148);
+		writel(0x00680000, addr + 0x1C8);
 	}
 
-	tmpbyte = readb(DEVADDR(0x4A));
+	tmpbyte = readb(addr + 0x4A);
 
-	proc_reports_siimage(dev, (tmpbyte>>=4), name);
+	proc_reports_siimage(dev, (tmpbyte>>4), name);
 	return 1;
 }
 
+/**
+ *	init_chipset_siimage	-	set up an SI device
+ *	@dev: PCI device
+ *	@name: device name
+ *
+ *	Perform the initial PCI set up for this device. Attempt to switch
+ *	to 133MHz clocking if the system isn't already set up to do it.
+ */
+
 static unsigned int __init init_chipset_siimage (struct pci_dev *dev, const char *name)
 {
 	u32 class_rev	= 0;
@@ -686,115 +926,134 @@
 			break;
 	}
 
-	pci_read_config_byte(dev, 0x8A, &tmpbyte);
-	pci_write_config_byte(dev, 0xA1, 0x72);
-	pci_write_config_word(dev, 0xA2, 0x328A);
+	pci_read_config_byte(dev,   0x8A, &tmpbyte);
+
+	pci_write_config_byte(dev,  0xA1, 0x72);
+	pci_write_config_word(dev,  0xA2, 0x328A);
 	pci_write_config_dword(dev, 0xA4, 0x62DD62DD);
 	pci_write_config_dword(dev, 0xA8, 0x43924392);
 	pci_write_config_dword(dev, 0xAC, 0x40094009);
-	pci_write_config_byte(dev, 0xB1, 0x72);
-	pci_write_config_word(dev, 0xB2, 0x328A);
+	pci_write_config_byte(dev,  0xB1, 0x72);
+	pci_write_config_word(dev,  0xB2, 0x328A);
 	pci_write_config_dword(dev, 0xB4, 0x62DD62DD);
 	pci_write_config_dword(dev, 0xB8, 0x43924392);
 	pci_write_config_dword(dev, 0xBC, 0x40094009);
 
-	pci_read_config_byte(dev, 0x8A, &tmpbyte);
-	proc_reports_siimage(dev, (tmpbyte>>=4), name);
+	proc_reports_siimage(dev, (tmpbyte>>4), name);
 	return 0;
 }
 
+/**
+ *	init_mmio_iops_siimage	-	set up the iops for MMIO
+ *	@hwif: interface to set up
+ *
+ *	The basic setup here is fairly simple, we can use standard MMIO
+ *	operations. However we do have to set the taskfile register offsets
+ *	by hand as there isnt a standard defined layout for them this
+ *	time.
+ *
+ *	The hardware supports buffered taskfiles and also some rather nice
+ *	extended PRD tables. Unfortunately right now we don't.
+ */
+ 
 static void __init init_mmio_iops_siimage (ide_hwif_t *hwif)
 {
 	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned long addr	= (unsigned long) pci_get_drvdata(hwif->pci_dev);
+	void *addr		= pci_get_drvdata(dev);
 	u8 ch			= hwif->channel;
-//	u16 i			= 0;
-	hw_regs_t hw;
+	hw_regs_t		hw;
+	unsigned long		base;
+
+	/*
+	 *	Fill in the basic HWIF bits
+	 */
 
 	default_hwif_mmiops(hwif);
+	hwif->hwif_data			= addr;
+
+	/*
+	 *	Now set up the hw. We have to do this ourselves as
+	 *	the MMIO layout isnt the same as the the standard port
+	 *	based I/O
+	 */
+	 
 	memset(&hw, 0, sizeof(hw_regs_t));
+	hw.priv				= addr;
 
-#if 1
-#ifdef SIIMAGE_BUFFERED_TASKFILE
-	hw.io_ports[IDE_DATA_OFFSET]	= DEVADDR((ch) ? 0xD0 : 0x90);
-	hw.io_ports[IDE_ERROR_OFFSET]	= DEVADDR((ch) ? 0xD1 : 0x91);
-	hw.io_ports[IDE_NSECTOR_OFFSET]	= DEVADDR((ch) ? 0xD2 : 0x92);
-	hw.io_ports[IDE_SECTOR_OFFSET]	= DEVADDR((ch) ? 0xD3 : 0x93);
-	hw.io_ports[IDE_LCYL_OFFSET]	= DEVADDR((ch) ? 0xD4 : 0x94);
-	hw.io_ports[IDE_HCYL_OFFSET]	= DEVADDR((ch) ? 0xD5 : 0x95);
-	hw.io_ports[IDE_SELECT_OFFSET]	= DEVADDR((ch) ? 0xD6 : 0x96);
-	hw.io_ports[IDE_STATUS_OFFSET]	= DEVADDR((ch) ? 0xD7 : 0x97);
-	hw.io_ports[IDE_CONTROL_OFFSET]	= DEVADDR((ch) ? 0xDA : 0x9A);
-#else /* ! SIIMAGE_BUFFERED_TASKFILE */
-	hw.io_ports[IDE_DATA_OFFSET]	= DEVADDR((ch) ? 0xC0 : 0x80);
-	hw.io_ports[IDE_ERROR_OFFSET]	= DEVADDR((ch) ? 0xC1 : 0x81);
-	hw.io_ports[IDE_NSECTOR_OFFSET]	= DEVADDR((ch) ? 0xC2 : 0x82);
-	hw.io_ports[IDE_SECTOR_OFFSET]	= DEVADDR((ch) ? 0xC3 : 0x83);
-	hw.io_ports[IDE_LCYL_OFFSET]	= DEVADDR((ch) ? 0xC4 : 0x84);
-	hw.io_ports[IDE_HCYL_OFFSET]	= DEVADDR((ch) ? 0xC5 : 0x85);
-	hw.io_ports[IDE_SELECT_OFFSET]	= DEVADDR((ch) ? 0xC6 : 0x86);
-	hw.io_ports[IDE_STATUS_OFFSET]	= DEVADDR((ch) ? 0xC7 : 0x87);
-	hw.io_ports[IDE_CONTROL_OFFSET]	= DEVADDR((ch) ? 0xCA : 0x8A);
-#endif /* SIIMAGE_BUFFERED_TASKFILE */
-#else
-#ifdef SIIMAGE_BUFFERED_TASKFILE
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
-		hw.io_ports[i] = DEVADDR((ch) ? 0xD0 : 0x90)|(i);
-	hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xDA : 0x9A);
-#else /* ! SIIMAGE_BUFFERED_TASKFILE */
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
-		hw.io_ports[i] = DEVADDR((ch) ? 0xC0 : 0x80)|(i);
-	hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xCA : 0x8A);
-#endif /* SIIMAGE_BUFFERED_TASKFILE */
-#endif
+	base				= (unsigned long)addr;
+	if(ch)
+		base += 0xC0;
+	else
+		base += 0x80;
 
-#if 0
-	printk(KERN_DEBUG "%s: ", hwif->name);
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
-		printk("0x%08x ", DEVADDR((ch) ? 0xC0 : 0x80)|(i));
-	printk("0x%08x ", DEVADDR((ch) ? 0xCA : 0x8A)|(i));
-#endif
+	/*
+	 *	The buffered task file doesn't have status/control
+	 *	so we can't currently use it sanely since we want to
+	 *	use LBA48 mode.
+	 */	
+//	base += 0x10;
+//      hwif->addressing = 1;
+
+	hw.io_ports[IDE_DATA_OFFSET]	= base;
+	hw.io_ports[IDE_ERROR_OFFSET]	= base + 1;
+	hw.io_ports[IDE_NSECTOR_OFFSET]	= base + 2;
+	hw.io_ports[IDE_SECTOR_OFFSET]	= base + 3;
+	hw.io_ports[IDE_LCYL_OFFSET]	= base + 4;
+	hw.io_ports[IDE_HCYL_OFFSET]	= base + 5;
+	hw.io_ports[IDE_SELECT_OFFSET]	= base + 6;
+	hw.io_ports[IDE_STATUS_OFFSET]	= base + 7;
+	hw.io_ports[IDE_CONTROL_OFFSET]	= base + 10;
 
 	hw.io_ports[IDE_IRQ_OFFSET]	= 0;
 
-        if (dev->device == PCI_DEVICE_ID_SII_3112) {
-		hw.sata_scr[SATA_STATUS_OFFSET]	= DEVADDR((ch) ? 0x184 : 0x104);
-		hw.sata_scr[SATA_ERROR_OFFSET]	= DEVADDR((ch) ? 0x188 : 0x108);
-		hw.sata_scr[SATA_CONTROL_OFFSET]= DEVADDR((ch) ? 0x180 : 0x100);
-		hw.sata_misc[SATA_MISC_OFFSET]	= DEVADDR((ch) ? 0x1C0 : 0x140);
-		hw.sata_misc[SATA_PHY_OFFSET]	= DEVADDR((ch) ? 0x1C4 : 0x144);
-		hw.sata_misc[SATA_IEN_OFFSET]	= DEVADDR((ch) ? 0x1C8 : 0x148);
+        if (pdev_is_sata(dev)) {
+        	base = (unsigned long) addr;
+        	if(ch)
+        		base += 0x80;
+		hw.sata_scr[SATA_STATUS_OFFSET]	= base + 0x104;
+		hw.sata_scr[SATA_ERROR_OFFSET]	= base + 0x108;
+		hw.sata_scr[SATA_CONTROL_OFFSET]= base + 0x100;
+		hw.sata_misc[SATA_MISC_OFFSET]	= base + 0x140;
+		hw.sata_misc[SATA_PHY_OFFSET]	= base + 0x144;
+		hw.sata_misc[SATA_IEN_OFFSET]	= base + 0x148;
 	}
 
-	hw.priv				= (void *) addr;
-//	hw.priv				= pci_get_drvdata(hwif->pci_dev);
 	hw.irq				= hwif->pci_dev->irq;
 
 	memcpy(&hwif->hw, &hw, sizeof(hw));
 	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
 
-	if (hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112) {
+	if (is_sata(hwif)) {
 		memcpy(hwif->sata_scr, hwif->hw.sata_scr, sizeof(hwif->hw.sata_scr));
 		memcpy(hwif->sata_misc, hwif->hw.sata_misc, sizeof(hwif->hw.sata_misc));
 	}
 
-#ifdef SIIMAGE_BUFFERED_TASKFILE
-        hwif->addressing = 1;
-#endif /* SIIMAGE_BUFFERED_TASKFILE */
 	hwif->irq			= hw.irq;
-	hwif->hwif_data			= pci_get_drvdata(hwif->pci_dev);
+
+       	base = (unsigned long) addr;
 
 #ifdef SIIMAGE_LARGE_DMA
-	hwif->dma_base			= DEVADDR((ch) ? 0x18 : 0x10);
-	hwif->dma_base2			= DEVADDR((ch) ? 0x08 : 0x00);
-	hwif->dma_prdtable		= (hwif->dma_base2 + 4);
+/* Watch the brackets - even Ken and Dennis get some language design wrong */
+	hwif->dma_base			= base + (ch ? 0x18 : 0x10);
+	hwif->dma_base2			= base + (ch ? 0x08 : 0x00);
+	hwif->dma_prdtable		= hwif->dma_base2 + 4;
 #else /* ! SIIMAGE_LARGE_DMA */
-	hwif->dma_base			= DEVADDR((ch) ? 0x08 : 0x00);
-	hwif->dma_base2			= DEVADDR((ch) ? 0x18 : 0x10);
+	hwif->dma_base			= base + (ch ? 0x08 : 0x00);
+	hwif->dma_base2			= base + (ch ? 0x18 : 0x10);
 #endif /* SIIMAGE_LARGE_DMA */
 	hwif->mmio			= 2;
 }
 
+/**
+ *	init_iops_siimage	-	set up iops
+ *	@hwif: interface to set up
+ *
+ *	Do the basic setup for the SIIMAGE hardware interface
+ *	and then do the MMIO setup if we can. This is the first
+ *	look in we get for setting up the hwif so that we
+ *	can get the iops right before using them.
+ */
+ 
 static void __init init_iops_siimage (ide_hwif_t *hwif)
 {
 	struct pci_dev *dev	= hwif->pci_dev;
@@ -802,27 +1061,47 @@
 
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;
+	
+	hwif->hwif_data = 0;
 
 	hwif->rqsize = 128;
-	if ((dev->device == PCI_DEVICE_ID_SII_3112) && (!(class_rev)))
-		hwif->rqsize = 16;
+	if (is_sata(hwif))
+		hwif->rqsize = 15;
 
 	if (pci_get_drvdata(dev) == NULL)
 		return;
 	init_mmio_iops_siimage(hwif);
 }
 
+/**
+ *	ata66_siimage	-	check for 80 pin cable
+ *	@hwif: interface to check
+ *
+ *	Check for the presence of an ATA66 capable cable on the
+ *	interface.
+ */
+ 
 static unsigned int __init ata66_siimage (ide_hwif_t *hwif)
 {
+	unsigned long addr = siimage_selreg(hwif, 0);
 	if (pci_get_drvdata(hwif->pci_dev) == NULL) {
 		u8 ata66 = 0;
-		pci_read_config_byte(hwif->pci_dev, SELREG(0), &ata66);
+		pci_read_config_byte(hwif->pci_dev, addr, &ata66);
 		return (ata66 & 0x01) ? 1 : 0;
 	}
 
-	return (hwif->INB(SELADDR(0)) & 0x01) ? 1 : 0;
+	return (hwif->INB(addr) & 0x01) ? 1 : 0;
 }
 
+/**
+ *	init_hwif_siimage	-	set up hwif structs
+ *	@hwif: interface to set up
+ *
+ *	We do the basic set up of the interface structure. The SIIMAGE
+ *	requires several custom handlers so we override the default
+ *	ide DMA handlers appropriately
+ */
+ 
 static void __init init_hwif_siimage (ide_hwif_t *hwif)
 {
 	hwif->autodma = 0;
@@ -833,7 +1112,7 @@
 	hwif->reset_poll = &siimage_reset_poll;
 	hwif->pre_reset = &siimage_pre_reset;
 
-	if(hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112)
+	if(is_sata(hwif))
 		hwif->busproc   = &siimage_busproc;
 
 	if (!hwif->dma_base) {
@@ -846,7 +1125,7 @@
 	hwif->mwdma_mask = 0x07;
 	hwif->swdma_mask = 0x07;
 
-	if (hwif->pci_dev->device != PCI_DEVICE_ID_SII_3112)
+	if (!is_sata(hwif))
 		hwif->atapi_dma = 1;
 
 	hwif->ide_dma_check = &siimage_config_drive_for_dma;
@@ -860,12 +1139,26 @@
 	} else {
 		hwif->ide_dma_test_irq = & siimage_io_ide_dma_test_irq;
 	}
-	if (!noautodma)
-		hwif->autodma = 1;
+	
+	/*
+	 *	The BIOS often doesn't set up DMA on this controller
+	 *	so we always do it.
+	 */
+
+	hwif->autodma = 1;
 	hwif->drives[0].autodma = hwif->autodma;
 	hwif->drives[1].autodma = hwif->autodma;
 }
 
+/**
+ *	init_dma_siimage	-	set up IDE DMA
+ *	@hwif: interface
+ *	@dmabase: DMA base address to use
+ *	
+ *	For the SI chips this requires no special set up so we can just
+ *	let the IDE DMA core do the usual work.
+ */
+ 
 static void __init init_dma_siimage (ide_hwif_t *hwif, unsigned long dmabase)
 {
 	ide_setup_dma(hwif, dmabase, 8);
@@ -874,6 +1167,15 @@
 extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
 
 
+/**
+ *	siimage_init_one	-	pci layer discovery entry
+ *	@dev: PCI device
+ *	@id: ident table entry
+ *
+ *	Called by the PCI code when it finds an SI680 or SI3112 controller.
+ *	We then use the IDE PCI generic helper to do most of the work.
+ */
+ 
 static int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
 	ide_pci_device_t *d = &siimage_chipsets[id->driver_data];
@@ -887,6 +1189,7 @@
 static struct pci_device_id siimage_pci_tbl[] __devinitdata = {
 	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
 	{ 0, },
 };
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)