Saturday, November 05, 2005

My patches to kernel 2.6.12-1.1381_FC3

That is a patch to allow:

SiS SATA 0182 support at the startup (I do not have an IDE hard drive to boot my Linux)
SiS Ethernet 0190 module driver
SiS 5513 IDE DMA support

Problem:
On original Fedora kernel there is no support on [sata_sis] module to the model 182 and it is not loaded at boot time.
There is no module to the SiS Ethernet controller model 190/191.
And there is no support to DMA on the SiS IDE controller model 5513.

Approach:
Apply all patches that I published, and apply to that situation, and modify the spec file to cope with the rpm kernel generation.

Remarks:
You should read and apply the partial patches already published, as follows:
sata_sis
sis190
sis5513

1. Get and install the kernel source that applies:
2.6.12-1.1381_FC3

2. Apply the above mentioned patches on the Remarks:

3. Script to pre-change all [.config] files:

Approach:
I prefer this script rather to create patches. I think it is more clear to understand what is going on here.
Basically I instruct the kernel to:

3.1. Add the SCSI support as a kernel internal instead of a loadable module:
CONFIG_SCSI=y
3.2. Add the SATA SCSI support for SiS as an internal:
CONFIG_SCSI_SATA_SIS=y
3.3. Add a NEW line to include the new driver, as a loadable module, for SiS Ethernet controller model 190/191 (that has no conterparter on this kernel).
CONFIG_SIS190=m

3.4. The script:

### /usr/src/redhat/SOURCES/make-config.sh ###
cat > /usr/src/redhat/SOURCES/make-config.sh << __END__
#!/bin/bash
# Please note that this script do NOT check if the [.config] was already patched
#
find /usr/src/redhat/SOURCES/ -name "*.config" -print | while read FILE
do
mv \${FILE} \${FILE}.orig
cat \${FILE}.orig | sed -e "s/\(CONFIG_SCSI=\)./\1y/" -e "s/\(CONFIG_SCSI_SATA_SIS=\).*/\1y/" -e "s/\(CONFIG_SIS900=m\)/\1\nCONFIG_SIS190=m/" > \${FILE}
done
__END__
chmod 700 /usr/src/redhat/SOURCES/make-config.sh
### /usr/src/redhat/SOURCES/make-config.sh ###

Note: Note that this script do NOT check if the files were already patched.

3.5. Executing the scritp, JUST ONCE:

/usr/src/redhat/SOURCES/make-config.sh

4. Patch the kernel spec file:

4.1. Patch file:

### /usr/src/redhat/SPECS/kernel-2.6.spec.patch ###
cat > /usr/src/redhat/SPECS/kernel-2.6.spec.patch << __END__
--- a/kernel-2.6.spec 2005-10-21 09:41:01.000000000 +0200
+++ b/kernel-2.6.spec 2005-11-05 16:31:20.000000000 +0100
@@ -19,7 +19,11 @@
%define sublevel 12
%define kversion 2.6.%{sublevel}
%define rpmversion 2.6.%{sublevel}
-%define rhbsys %([ -r /etc/beehive-root -o -n "%{?__beehive_build}" ] && echo || echo .`whoami`)
+#
+# I just do no like Fedora standard names for self-made kernels, so I call it just [sis]
+#
+#%define rhbsys %([ -r /etc/beehive-root -o -n "%{?__beehive_build}" ] && echo || echo .`whoami`)
+%define rhbsys sis
%define release %(R="$Revision: 1.1381 $"; RR="${R##: }"; echo ${RR%%?})_FC3%{rhbsys}
%define signmodules 0
%define make_target bzImage
@@ -162,6 +166,7 @@


Source0: ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-%{kversion}.tar.bz2
+Source1: linux-2.6.12-sis190.tar.bz2

Source10: COPYING.modules
Source11: genkey
@@ -201,6 +206,8 @@
Patch301: linux-2.6.12-serial-of.patch
Patch302: linux-2.6.10-ppc-headerabuse.patch
Patch303: linux-2.6-windtunnel-printk.patch
+Patch304: linux-2.6.12-sis190-Kconfig.patch
+Patch305: linux-2.6.12-sis190-Makefile.patch

# 400 - 499 ia64
Patch400: linux-2.6.3-ia64-build.patch
@@ -248,6 +255,8 @@
Patch1060: linux-2.6.3-crash-driver.patch
Patch1070: linux-2.6.0-sleepon.patch

+Patch1080: linux-2.6.12-sis5513.patch
+
# SCSI bits.
Patch1101: linux-2.6.9-scsi-advansys-enabler.patch
Patch1102: linux-2.6.9-scsi-megaraid-legacy.patch
@@ -255,6 +264,8 @@
Patch1104: linux-2.6.12-scsicam-geom-fix.patch
Patch1105: linux-2.6-scsi-sym2-alloc_lcb_tags-atomic.patch
Patch1106: linux-2.6-scsi-aic-dma39bit.patch
+Patch1107: linux-2.6.12-sata_sis182-light.patch
+Patch1108: linux-2.6.12-sata_sis182.patch

# NFS bits.
Patch1200: linux-2.6.9-NFSD-non-null-getxattr.patch
@@ -418,6 +429,10 @@
rm -rf linux-%{kversion}
cp -rl vanilla linux-%{kversion}

+#
+# Here I'm ashamed, I really do not known how to do that with more elegancy
+#
+tar -xjf %{SOURCE1}
cd linux-%{kversion}

#
@@ -451,6 +466,9 @@
%patch301 -p1
%patch302 -p1
%patch303 -p1
+# Patch for sis190 NIC
+%patch304 -p1
+%patch305 -p1

#
# ia64
@@ -554,6 +572,11 @@
%patch1070 -p1

#
+# SiS 5513 DMA support
+#
+%patch1080 -p1
+
+#
# SCSI Bits.
#
# Enable Advansys driver
@@ -568,6 +591,11 @@
%patch1105 -p1
# Fix aic7xxx >4GB
%patch1106 -p1
+# Fix sata_sis suport to sis182
+# light version, just an ID tag added
+%patch1107 -p1
+# complete version from SiS, but does not boot
+#%patch1108 -p1

#
# Various upstream NFS/NFSD fixes.
__END__
### /usr/src/redhat/SPECS/kernel-2.6.spec.patch ###

4.2. Applying the patch:

cd /usr/src/redhat/SPECS/
patch -p1 < kernel-2.6.spec.patch

5. Making the RPMs from spec:

cd /usr/src/redhat/SPECS/

5.1. Clean previous build (do NOT forget this):

rpmbuild --clean kernel-2.6.spec ### clean all

5.2. Build all for your platform, it may be one of them so please take the one that applies to you:

# rpmbuild -ba --target=i586 kernel-2.6.spec ### to install from a CD
# rpmbuild -ba --target=i686 kernel-2.6.spec ### I use this one
# rpmbuild -ba --target=x86_64 kernel-2.6.spec ### AMD64

Note: Of course there are more options, but for a regular user these ones above must cover most of the cases.

5.3. Take time to see a film, read a book or something else, because it will take long (from 2 to 3 hours).

6. Install the new kernel, that will be written at: [/usr/src/redhat/RPMS/], in my case:

rpm -Uvhi /usr/src/redhat/RPMS/i686/kernel-2.6.12-1.1381_FC3sis.i686.rpm
rpm -Uvhi /usr/src/redhat/RPMS/i686/kernel-smp-2.6.12-1.1381_FC3sis.i686.rpm

7. Test it and adjust the GRUB configuration to boot with the new kernel (if it wasn't already done), it is at: [/etc/grub.conf]

8. Say thanks if it works or what goes wrong :-).

Please always address to my hardware, os and kernel patching general procedures before posting a question.

SiS IDE Controller 5513 [sis5513] patch, try 2

Supported (tested) kernels:
2.6.12-1.1381_FC3

Problem:
On original Fedora kernel there is no support to DMA on the SiS IDE controller model 5513.
Go figure why on the file [sis5513] there is no string to address DMA setup to the "SiS5513" chipset, maybe sooner support and no rework after that.

Approach:
Modify the module source to recognise the controller hardware.
In this case the south bridge controller: SiS965.

Remarks:
RPM kernel spec file part will be covered on the kernel specific part.

1. Get and install the kernel source that applies:

2. Patch to the file [sis5513.c]:

### /usr/src/redhat/SOURCES/linux-2.6.12-sis5513.patch ###
cat > /usr/src/redhat/SOURCES/linux-2.6.12-sis5513.patch << __END__
--- a/drivers/ide/pci/sis5513.c 2005-11-05 19:26:57.000000000 +0100
+++ b/drivers/ide/pci/sis5513.c 2005-11-05 19:31:10.000000000 +0100
@@ -87,6 +87,8 @@
u8 chipset_family;
u8 flags;
} SiSHostChipInfo[] = {
+ { "SiS695", PCI_DEVICE_ID_SI_965, ATA_133 },
+
{ "SiS745", PCI_DEVICE_ID_SI_745, ATA_100 },
{ "SiS735", PCI_DEVICE_ID_SI_735, ATA_100 },
{ "SiS733", PCI_DEVICE_ID_SI_733, ATA_100 },
--- a/include/linux/pci_ids.h 2005-11-05 19:38:13.000000000 +0100
+++ b/include/linux/pci_ids.h 2005-11-05 19:39:18.000000000 +0100
@@ -661,6 +661,7 @@
#define PCI_DEVICE_ID_SI_961 0x0961
#define PCI_DEVICE_ID_SI_962 0x0962
#define PCI_DEVICE_ID_SI_963 0x0963
+#define PCI_DEVICE_ID_SI_965 0x0965
#define PCI_DEVICE_ID_SI_5107 0x5107
#define PCI_DEVICE_ID_SI_5300 0x5300
#define PCI_DEVICE_ID_SI_5511 0x5511
__END__
### /usr/src/redhat/SOURCES/linux-2.6.12-sis5513.patch ###

Please always address to my hardware, os and kernel patching general procedures before posting a question.

SiS IDE Controller 5513 [sis5513] patch, try 1

Supported (tested) kernels:
2.6.12-1.1381_FC3

Problem:
On original Fedora kernel there is no support to DMA on the SiS IDE controller model 5513.
Go figure why on the file [sis5513] there is no string to address DMA setup to the "SiS5513" chipset, maybe sooner support and no rework after that.

Approach:
Modify the module source to recognise the controller hardware.

Remarks:
RPM kernel spec file part will be covered on the kernel specific part.

1. Get and install the kernel source that applies :

2. Patch to the file [sis5513.c]:

### /usr/src/redhat/SOURCES/linux-2.6.12-sis5513.patch ###
cat > /usr/src/redhat/SOURCES/linux-2.6.12-sis5513.patch << __END__
--- a/drivers/ide/pci/sis5513.c 2005-11-05 12:29:17.000000000 +0100
+++ b/drivers/ide/pci/sis5513.c 2005-11-05 12:29:37.000000000 +0100
@@ -112,6 +112,7 @@
{ "SiS5596", PCI_DEVICE_ID_SI_5596, ATA_16 },
{ "SiS5571", PCI_DEVICE_ID_SI_5571, ATA_16 },
{ "SiS551x", PCI_DEVICE_ID_SI_5511, ATA_16 },
+ { "SiS5513", PCI_DEVICE_ID_SI_5511, ATA_133 },
};

/* Cycle time bits and values vary across chip dma capabilities
__END__
### /usr/src/redhat/SOURCES/linux-2.6.12-sis5513.patch ###

Please always address to my hardware, os and kernel patching general procedures before posting a question.

SiS Ethernet 0190 [sis190] patch, try 1

Supported (tested) kernels:
2.6.12-1.1378_FC3
2.6.12-1.1381_FC3

Problem:
On original Fedora kernel there is no module to the SiS Ethernet controller model 190/191.

Approach:
Get the driver from SiS and patch the kernel to recognise it and compile it.

Remarks:
RPM kernel spec file part will be covered on the kernel specific part.

1. Get and install the kernel source that applies :

2. Get the SiS driver for Linux
To take the driver by yourself go to SiS download center and chose:
Network Driver -> SiS190 Gigabit & SiS191 LAN -> Linux -> GO
Than proceed to the download of "SiS190 / SiS191 Gigabit LAN / LAN driver for Linux kernal 2.6.9 or later."

3. Extract the file [sis190.c] and repack it like this:

tar -vxzf sis190191_linux.tar.gz # file from SiS
mkdir -p linux-2.6.12/drivers/net/
cp sis190_20041220/sis190.c linux-2.6.12/drivers/net/
tar -vcjf /usr/src/redhat/SOURCES/linux-2.6.12-sis190.tar.bz2 linux-2.6.12/drivers/net/sis190.c

4. Patch to the [.config] file, so the module will be compiled:

### /usr/src/redhat/SOURCES/linux-2.6.12-sis190-config.patch ###
cat > /usr/src/redhat/SOURCES/linux-2.6.12-sis190-config.patch << __END__
--- a/.config 2005-09-29 10:37:15.000000000 +0200
+++ b/.config 2005-09-29 10:42:06.000000000 +0200
@@ -1255,6 +1255,7 @@ CONFIG_8139TOO_PIO=y
CONFIG_8139TOO_8129=y
# CONFIG_8139_OLD_RX_RESET is not set
CONFIG_SIS900=m
+CONFIG_SIS190=m
CONFIG_EPIC100=m
CONFIG_SUNDANCE=m
# CONFIG_SUNDANCE_MMIO is not set
__END__
### /usr/src/redhat/SOURCES/linux-2.6.12-sis190-config.patch ###

5. Patch to Kernel network [Kconfig] file:

### /usr/src/redhat/SOURCES/linux-2.6.12-sis190-Kconfig.patch ###
cat > /usr/src/redhat/SOURCES/linux-2.6.12-sis190-Kconfig.patch << __END__
--- a/drivers/net/Kconfig 2005-06-17 21:48:29.000000000 +0200
+++ b/drivers/net/Kconfig 2005-09-29 10:41:13.000000000 +0200
@@ -1571,6 +1571,16 @@ config SIS900
To compile this driver as a module, choose M here: the module
will be called sis900. This is recommended.

+config SIS190
+ tristate "SiS 191/190 PCI Gigabit/Fast Ethernet Adapter support"
+ depends on NET_PCI && PCI
+ select CRC32
+ ---help---
+ Say Y here if you have a SiS 191/190 PCI Gigabit/Fast Ethernet adapter.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sis190. This is recommended.
+
config EPIC100
tristate "SMC EtherPower II"
depends on NET_PCI && PCI
__END__
### /usr/src/redhat/SOURCES/linux-2.6.12-sis190-Kconfig.patch ###

6. Patch to network makefile:

### /usr/src/redhat/SOURCES/linux-2.6.12-sis190-Makefile.patch ###
cat > /usr/src/redhat/SOURCES/linux-2.6.12-sis190-Makefile.patch << __END__
--- a/drivers/net/Makefile 2005-09-29 10:37:07.000000000 +0200
+++ b/drivers/net/Makefile 2005-09-29 10:40:51.000000000 +0200
@@ -43,6 +43,7 @@ obj-$(CONFIG_E100) += e100.o
obj-$(CONFIG_TLAN) += tlan.o
obj-$(CONFIG_EPIC100) += epic100.o
obj-$(CONFIG_SIS900) += sis900.o
+obj-$(CONFIG_SIS900) += sis190.o
obj-$(CONFIG_YELLOWFIN) += yellowfin.o
obj-$(CONFIG_ACENIC) += acenic.o
obj-$(CONFIG_ISERIES_VETH) += iseries_veth.o
__END__
### /usr/src/redhat/SOURCES/linux-2.6.12-sis190-Makefile.patch ###



Please always address to my hardware, os and kernel patching general procedures before posting a question.

SiS SATA 0182 [sata_sis] patches, Light and Complete, try 1

Supported (tested) kernels:
2.6.9-1.667
2.6.12-1.1378_FC3
2.6.12-1.1381_FC3

Problem:
On original Fedora kernel there is no support on [sata_sis] module to the model 182 and it is not loaded at boot time.

Approach:
Modify the module source to recognise the controller hardware.

Remarks:
RPM kernel spec file part will be covered on the kernel specific part.

1. Get and install the kernel source that applies :

2. Add the following patches to [/usr/src/redhat/SOURCES/]:

OBS.: If you execute the "cat" commands it will be create on the right place. Do not be so untruthful :-).

2.1. Light version (that works):

Approach:
Just add the ID tag to the module corresponding struct.

### /usr/src/redhat/SOURCES/linux-2.6.12-sata_sis182-light.patch ###
cat > /usr/src/redhat/SOURCES/linux-2.6.12-sata_sis182-light.patch << __END__
--- a/drivers/scsi/sata_sis.c 2005-06-17 21:48:29.000000000 +0200
+++ b/drivers/scsi/sata_sis.c 2005-09-29 19:05:45.012291288 +0200
@@ -62,6 +62,7 @@ static void sis_scr_write (struct ata_po
static struct pci_device_id sis_pci_tbl[] = {
{ PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
{ PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+ { PCI_VENDOR_ID_SI, 0x182, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
{ } /* terminate list */
};

__END__
### /usr/src/redhat/SOURCES/linux-2.6.12-sata_sis182-light.patch ###

2.2. Complete version (does not work and I do know why):

Approach:
Use the patch given by SiS to cope with the problem.

OBS.:
To take the driver by yourself go to SiS download center and chose:
Chipset Software -> SATA & RAID -> Linux -> GO
Than proceed to the download of "SiS SATA Driver for Linux (kernel2.6.10)"

### /usr/src/redhat/SOURCES/linux-2.6.12-sata_sis182.patch ###
cat > /usr/src/redhat/SOURCES/linux-2.6.12-sata_sis182.patch << __END__
--- a/drivers/scsi/sata_sis.c 2005-06-17 21:48:29.000000000 +0200
+++ b/drivers/scsi/sata_sis.c 2005-09-29 11:14:08.000000000 +0200
@@ -39,15 +39,19 @@

#define DRV_NAME "sata_sis"
#define DRV_VERSION "0.5"
-
+#define ATA_DEBUG
enum {
sis_180 = 0,
+ sis_182 = 1,
SIS_SCR_PCI_BAR = 5,
-
+ SIS_ALLOC_PRIV_SIZE = 0x10,
/* PCI configuration registers */
SIS_GENCTL = 0x54, /* IDE General Control register */
SIS_SCR_BASE = 0xc0, /* sata0 phy SCR registers */
SIS_SATA1_OFS = 0x10, /* offset from sata0->sata1 phy regs */
+ SIS_PMR = 0x90, /* port mapping register */
+ SIS_CHANNEL_CTRL = 0x50, /* primary channel control register */
+ ATA_DEV_RESET = 0x08, /* Device Reset command */

/* random bits */
SIS_FLAG_CFGSCR = (1 << 30), /* host flag: SCRs via PCI cfg */
@@ -58,10 +62,17 @@ enum {
static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static void sis_port_reset(struct ata_port *ap);
+static void sis_set_piomode (struct ata_port *ap, struct ata_device *dev);
+static void sis_set_dmamode (struct ata_port *ap, struct ata_device *dev);
+static int sis_port_start(struct ata_port *ap);
+static void sis_port_stop(struct ata_port *ap);
+static void sis_qc_prep(struct ata_queued_cmd *qc);

static struct pci_device_id sis_pci_tbl[] = {
{ PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
{ PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+ { PCI_VENDOR_ID_SI, 0x182, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_182 },
{ } /* terminate list */
};

@@ -90,102 +101,525 @@ static Scsi_Host_Template sis_sht = {
.dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
.bios_param = ata_std_bios_param,
- .ordered_flush = 1,
};

static struct ata_port_operations sis_ops = {
.port_disable = ata_port_disable,
+ .set_piomode = sis_set_piomode,
+ .set_dmamode = sis_set_dmamode,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .phy_reset = sata_phy_reset,
- .bmdma_setup = ata_bmdma_setup,
+ .phy_reset = sis_port_reset,
+ .bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
- .bmdma_stop = ata_bmdma_stop,
- .bmdma_status = ata_bmdma_status,
- .qc_prep = ata_qc_prep,
+ .qc_prep = sis_qc_prep,
.qc_issue = ata_qc_issue_prot,
.eng_timeout = ata_eng_timeout,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.scr_read = sis_scr_read,
.scr_write = sis_scr_write,
- .port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
+ .port_start = sis_port_start,
+ .port_stop = sis_port_stop,
};

static struct ata_port_info sis_port_info = {
.sht = &sis_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
- ATA_FLAG_NO_LEGACY,
+ .host_flags = ATA_FLAG_SATA | ATA_FLAG_SLAVE_POSS |
+ ATA_FLAG_NO_LEGACY,
.pio_mask = 0x1f,
.mwdma_mask = 0x7,
.udma_mask = 0x7f,
.port_ops = &sis_ops,
};

+struct sis_port_priv {
+ u32 addr;
+ u32 pad_phy_addr;
+};

MODULE_AUTHOR("Uwe Koziolek");
MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
+MODULE_VERSION();
+

-static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg)
+void sis_qc_prep(struct ata_queued_cmd *qc)
{
- unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
+ struct scatterlist *sg = qc->sg;
+ struct ata_port *ap = qc->ap;
+ unsigned int idx, nelem;
+ struct sis_port_priv * sis_priv;
+
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+ return;
+
+ assert(sg != NULL);
+ assert(qc->n_elem > 0);

- if (port_no)
- addr += SIS_SATA1_OFS;
- return addr;
+ idx = 0;
+ for (nelem = qc->n_elem; nelem; nelem--,sg++) {
+ u32 addr, offset;
+ u32 sg_len, len;
+
+ /* determine if physical DMA addr spans 64K boundary.
+ * Note h/w doesn't support 64-bit, so we unconditionally
+ * truncate dma_addr_t to u32.
+ */
+ addr = (u32) sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ while (sg_len) {
+ offset = addr & 0xffff;
+ len = sg_len;
+ if ((offset + sg_len) > 0x10000)
+ len = 0x10000 - offset;
+
+ ap->prd[idx].addr = cpu_to_le32(addr);
+ ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+
+ idx++;
+ sg_len -= len;
+ addr += len;
+ }
+ }
+
+ if (idx){
+ /**
+ SATA transcation is DWORD unit, need to pad WORD for ODD-WORD request
+ for SiS controller
+ */
+ if ((ap->prd[idx - 1].flags_len %4) != 0)
+ {
+ sis_priv = (struct sis_port_priv *)ap->private_data;
+ DPRINTK ("PRD[%u]_ADDR = 0x%X\n", idx-1, ap->prd[idx-1].addr);
+ DPRINTK ("PRD[%u]_LEN = 0x%X\n", idx-1, ap->prd[idx-1].flags_len);
+ ap->prd[idx].addr = cpu_to_le32(sis_priv->pad_phy_addr);
+ ap->prd[idx].flags_len = 2|cpu_to_le32(ATA_PRD_EOT);
+ DPRINTK ("PRD[%u]_ADDR = 0x%X\n", idx, ap->prd[idx].addr);
+ DPRINTK ("PRD[%u]_LEN = 0x%X\n", idx, ap->prd[idx].flags_len);
+ }
+ else {
+ ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+ }
+ }
}

-static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
+int sis_port_start(struct ata_port *ap)
{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
- unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg);
- u32 val;
+ struct device *dev = ap->host_set->dev;
+ u8 * buf;
+ struct sis_port_priv * sis_priv;
+
+ buf = kmalloc(SIS_ALLOC_PRIV_SIZE, GFP_KERNEL);
+ if (!buf) {
+ return -ENOMEM;
+ }
+
+ sis_priv = (struct sis_port_priv *)buf;
+ ap->private_data = sis_priv;
+ // record the phy_addr of the padding buffer, offset by 4 from requested priv_data, for later use.
+ sis_priv->pad_phy_addr = dma_map_single(dev, buf+sizeof(u32), sizeof(u16), DMA_BIDIRECTIONAL);
+ ap->prd = dma_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma, GFP_KERNEL);
+
+ if (!ap->prd){
+ kfree(buf);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void sis_port_stop(struct ata_port *ap)
+{
+ struct device *dev = ap->host_set->dev;
+ struct sis_port_priv * sis_priv = (struct sis_port_priv *)ap->private_data;

- if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
- return 0xffffffff;
- pci_read_config_dword(pdev, cfg_addr, &val);
- return val;
+ dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
+ // umap the padding buffer.
+ dma_unmap_single(dev, sis_priv->pad_phy_addr, sizeof(u16), DMA_BIDIRECTIONAL);
+ kfree(ap->private_data);
}

-static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
+
+static void sis_set_piomode (struct ata_port *ap, struct ata_device *dev)
{
struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
- unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr);
+ static const
+ u8 timings[][3] = { { 9, 38, 40 },
+ { 6, 38, 12 },
+ { 3, 38, 4 },
+ { 3, 10, 12 },
+ { 3, 9, 5 } };
+ u32 val;
+ u8 reg = (dev->devno)?0x44:0x40;
+
+ if (pdev->device == 0x182)
+ return;
+ if (ap->port_no != 0)
+ return;
+
+ pci_read_config_dword(pdev, reg, &val);
+ val = (val & ~0xf000) | (u32)timings[dev->pio_mode-8][0]<<12;
+ val = (val & ~0x3f0000) | (u32)timings[dev->pio_mode-8][1]<<16;
+ val = (val & ~0x3f000000) | (u32)timings[dev->pio_mode-8][2]<<24;
+ pci_write_config_dword(pdev, reg, val);

- if (scr == SCR_ERROR) /* doesn't exist in PCI cfg space */
+}
+
+/*
+ Only 180/181 device need to set controller timing.
+*/
+static void sis_set_dmamode (struct ata_port *ap, struct ata_device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+ static const
+ u8 timings[][2] = { { 15, 9 },
+ { 10, 6 },
+ { 7, 4 },
+ { 5, 2 },
+ { 3, 2 },
+ { 2, 2 },
+ { 1, 2 } };
+ u32 val;
+ u8 reg = (dev->devno)?0x44:0x40;
+
+ if (pdev->device == 0x182)
+ return;
+ if (ap->port_no != 0)
return;
- pci_write_config_dword(pdev, cfg_addr, val);
+
+ pci_read_config_dword(pdev, reg, &val);
+ val = (val & ~0xf0) | (u32)timings[dev->dma_mode&0xf][0]<<4;
+ val = (val & ~0xf00) | (u32)timings[dev->dma_mode&0xf][1]<<8;
+ pci_write_config_dword(pdev, reg, val);
+
+}
+
+
+static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+ unsigned int cfg_addr;
+ u8 tmp;
+ u32 val, val2;
+
+ // 180 / 181
+ if (pdev->device != 0x182) {
+ pci_read_config_byte(pdev, SIS_PMR, &tmp);
+ // no pata
+ if ((tmp & 0x30)== 0) {
+ if (ap->port_no == 0)
+ cfg_addr = 0xc0;
+ else
+ cfg_addr = 0xd0;
+ pci_read_config_dword(pdev, cfg_addr+sc_reg*4, &val);
+ return val;
+ }
+ else
+ cfg_addr = 0xc0;
+ }
+ else {
+ if (ap->port_no == 0)
+ cfg_addr = 0xc0;
+ else
+ cfg_addr = 0xe0;
+ }
+
+ pci_read_config_dword(pdev, cfg_addr+sc_reg*4, &val);
+ pci_read_config_dword(pdev, cfg_addr+sc_reg*4+0x10, &val2);
+ if (val == 0 && val2 == 0)
+ return val;
+ else
+ return val|val2;
+}
+
+static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+ unsigned int cfg_addr;
+ u8 tmp;
+
+ // 180 / 181
+ if (pdev->device != 0x182) {
+ pci_read_config_byte(pdev, SIS_PMR, &tmp);
+ // no pata
+ if ((tmp & 0x30)== 0) {
+ if (ap->port_no == 0)
+ cfg_addr = 0xc0;
+ else
+ cfg_addr = 0xd0;
+ pci_write_config_dword(pdev, cfg_addr+scr*4, val);
+ return;
+ }
+ else
+ cfg_addr = 0xc0;
+ }
+ // 182, one should not have chance to see
+ else {
+ if (ap->port_no == 0)
+ cfg_addr = 0xc0;
+ else
+ cfg_addr = 0xe0;
+ }
+
+ pci_write_config_dword(pdev, cfg_addr+scr*4, val);
+ pci_write_config_dword(pdev, cfg_addr+scr*4+0x10, val);
}

static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
+ u32 result, result2;
+ u8 tmp;
+
if (sc_reg > SCR_CONTROL)
return 0xffffffffU;

- if (ap->flags & SIS_FLAG_CFGSCR)
+ if (ap->flags & SIS_FLAG_CFGSCR) {
return sis_scr_cfg_read(ap, sc_reg);
- return inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ }
+ else {
+ // 180 / 181
+ if (to_pci_dev(ap->host_set->dev)->device != 0x182) {
+ pci_read_config_byte(to_pci_dev(ap->host_set->dev), SIS_PMR, &tmp);
+ // no pata
+ if ((tmp & 0x30)== 0)
+ return inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ // combined mode
+ else {
+ result = inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ result2 = inl(ap->ioaddr.scr_addr+0x10 + (sc_reg * 4));
+ if (result == 0 && result2 == 0)
+ return result;
+ else
+ return result|result2;
+ }
+ }
+ // 182
+ else {
+ result = inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ result2 = inl(ap->ioaddr.scr_addr+0x10 + (sc_reg * 4));
+ if (result == 0 && result2 == 0)
+ return result;
+ else
+ return result|result2;
+ }
+ }
}

static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
{
+ u8 tmp;
if (sc_reg > SCR_CONTROL)
return;

if (ap->flags & SIS_FLAG_CFGSCR)
sis_scr_cfg_write(ap, sc_reg, val);
+
+ else {
+ // 180 / 181
+ if (to_pci_dev(ap->host_set->dev)->device != 0x182) {
+ pci_read_config_byte(to_pci_dev(ap->host_set->dev), SIS_PMR, &tmp);
+
+ // no pata
+ if ((tmp & 0x30)== 0) {
+ outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ }
+ // combined mode
+ else {
+ outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ outl(val, ap->ioaddr.scr_addr + 0x10 + (sc_reg * 4));
+ }
+ }
+ // 182
+ else {
+ outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ outl(val, ap->ioaddr.scr_addr + 0x10 + (sc_reg * 4));
+ }
+ }
+}
+
+/**
+ flag = 1, enable PCI int
+ flag = 0, disable PCI int
+*/
+void sis_set_int(struct ata_port *ap, int flag)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+ u32 tmp;
+
+ pci_read_config_dword(pdev, PCI_COMMAND, &tmp);
+ if (flag)
+ tmp &= ~PCI_COMMAND_INTX_DISABLE;
+ else
+ tmp |= PCI_COMMAND_INTX_DISABLE;
+
+ pci_write_config_dword(pdev, PCI_COMMAND, tmp);
+}
+
+unsigned int sis_busy_sleep (struct ata_port *ap,
+ unsigned long tmout_pat,
+ unsigned long tmout)
+{
+ unsigned long timer_start, timeout;
+ u8 status;
+
+ status = ata_busy_wait(ap, ATA_BUSY, 300);
+ timer_start = jiffies;
+ timeout = timer_start + tmout_pat;
+ while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
+ msleep(50);
+ status = ata_busy_wait(ap, ATA_BUSY, 3);
+ }
+
+ if (status & ATA_BUSY)
+ DPRINTK(KERN_WARNING "ata%u is slow to respond, "
+ "please be patient\n", ap->id);
+
+ timeout = timer_start + tmout;
+ while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
+ msleep(50);
+ status = ata_chk_status(ap);
+ }
+
+ if (status & ATA_BUSY) {
+ DPRINTK(KERN_ERR "ata%u failed to respond (%lu secs)\n",
+ ap->id, tmout / HZ);
+ return 1;
+ }
+
+ return 0;
+}
+
+void sis_bus_reset(struct ata_port *ap)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ struct ata_taskfile tf;
+ struct ata_device *dev;
+ u8 status;
+ int i;
+
+ sis_set_int (ap, 0);
+
+ for ( i = 0; i < 2; i++) {
+ dev = &ap->device[i];
+ dev->class = ATA_DEV_NONE;
+ // clear signature register
+ outb(0, ioaddr->lbam_addr);
+ outb(0, ioaddr->lbah_addr);
+ // select the device
+ ap->ops->dev_select(ap, i);
+ // issue device reset command
+ outb (ATA_DEV_RESET, ioaddr->command_addr);
+ // wait....
+ msleep(500);
+ // read it back
+ memset(&tf, 0, sizeof(tf));
+ ap->ops->tf_read(ap, &tf);
+ if (((tf.lbam == 0x14) && (tf.lbah == 0xeb))) {
+ DPRINTK("found ATAPI device by sig\n");
+ dev->class = ATA_DEV_ATAPI;
+ continue;
+ }
+ else {
+ status = ata_check_status(ap);
+ if ((status & 0xf0) == 0x50) {
+ DPRINTK("found ATA device by sig\n");
+ dev->class = ATA_DEV_ATA;
+ }
+ else {
+ DPRINTK("unknown device\n");
+ dev->class = ATA_DEV_UNKNOWN;
+ }
+ }
+ }
+ sis_set_int (ap, 1);
+}
+
+
+void sis_sata_reset(struct ata_port *ap)
+{
+ unsigned long timeout = jiffies + (HZ * 5);
+ u32 sstatus;
+
+ scr_write(ap, SCR_CONTROL, 0x301); /* issue phy wake/reset */
+ msleep(50);
+ scr_write(ap, SCR_CONTROL, 0x300);
+ msleep(500);
+ scr_write(ap, SCR_ERROR, 0xffffffff);
+ /* wait for phy to become ready, if necessary */
+ do {
+ msleep(100);
+ sstatus = scr_read(ap, SCR_STATUS);
+ if ((sstatus & 0xf) != 1)
+ break;
+ } while (time_before(jiffies, timeout));
+
+ if (sata_dev_present(ap))
+ ata_port_probe(ap);
+ else {
+ sstatus = scr_read(ap, SCR_STATUS);
+ DPRINTK(KERN_INFO "ata%u: no device found (phy stat %08x)\n", ap->id, sstatus);
+ ata_port_disable(ap);
+ }
+ ap->cbl = ATA_CBL_SATA;
+}
+
+static void sis_port_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+ u8 tmp;
+ int i;
+
+ /* Reset routine for 180 | 181 need specail care...*/
+ if (pdev->device != 0x182) {
+ pci_read_config_byte(pdev, SIS_PMR, &tmp);
+ /* combined mode */
+ if ((tmp & 0x30)!= 0) {
+ if (ap->port_no == 0) {
+ ata_port_probe(ap);
+ // detect cable type
+ pci_read_config_byte(pdev, SIS_CHANNEL_CTRL, &tmp);
+ if (tmp & 0x1) {
+ DPRINTK ("PATA use 40pin cable\n");
+ ap->cbl = ATA_CBL_PATA40;
+ ap->udma_mask &= ATA_UDMA_MASK_40C;
+ }
+ else {
+ DPRINTK ("PATA use 80pin cable\n");
+ ap->cbl = ATA_CBL_PATA80;
+ }
+ }
+ /* pure sata mode, one device one channel */
+ else
+ sis_sata_reset(ap);
+ }
+ // pure sata mode
+ else
+ sis_sata_reset(ap);
+ }
+ /* for 182 section */
else
- outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ sis_sata_reset(ap);
+
+ if (ap->flags & ATA_FLAG_PORT_DISABLED)
+ return;
+ // give device chances to be ready
+ for ( i = 0; i<10; i++)
+ {
+ tmp = inb(ap->ioaddr.status_addr);
+ if (tmp == 0x80)
+ msleep(50);
+ }
+
+ sis_bus_reset(ap);
}

+
/* move to PCI layer, integrate w/ MSI stuff */
static void pci_enable_intx(struct pci_dev *pdev)
{
@@ -204,17 +638,15 @@ static int sis_init_one (struct pci_dev
int rc;
u32 genctl;
struct ata_port_info *ppi;
- int pci_dev_busy = 0;
-
+ u8 tmp;
+
rc = pci_enable_device(pdev);
if (rc)
return rc;

rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
+ if (rc)
goto err_out;
- }

rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
@@ -229,7 +661,7 @@ static int sis_init_one (struct pci_dev
rc = -ENOMEM;
goto err_out_regions;
}
-
+
/* check and see if the SCRs are in IO space or PCI cfg space */
pci_read_config_dword(pdev, SIS_GENCTL, &genctl);
if ((genctl & GENCTL_IOMAPPED_SCR) == 0)
@@ -247,12 +679,33 @@ static int sis_init_one (struct pci_dev
}

if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) {
- probe_ent->port[0].scr_addr =
- pci_resource_start(pdev, SIS_SCR_PCI_BAR);
- probe_ent->port[1].scr_addr =
- pci_resource_start(pdev, SIS_SCR_PCI_BAR) + 64;
+ if (ent->driver_data == sis_180) {
+ pci_read_config_byte(pdev, SIS_PMR, &tmp);
+ if ((tmp & 0x30)== 0) {
+ DPRINTK ("SiS-180/181 pure sata mode detected\n");
+ probe_ent->port[0].scr_addr = pci_resource_start(pdev, SIS_SCR_PCI_BAR);
+ probe_ent->port[1].scr_addr = pci_resource_start(pdev, SIS_SCR_PCI_BAR) + 64;
+ }
+ else {
+ DPRINTK ("SiS-180/181 combined mode detected!\n");
+ probe_ent->port[1].scr_addr = pci_resource_start(pdev, SIS_SCR_PCI_BAR);
+ }
+ }
+ if (ent->driver_data == sis_182) {
+ probe_ent->port[0].scr_addr = pci_resource_start(pdev, SIS_SCR_PCI_BAR);
+ probe_ent->port[1].scr_addr = pci_resource_start(pdev, SIS_SCR_PCI_BAR) + 0x20;
+ }
}
-
+ else {
+ if (ent->driver_data == sis_180) {
+ pci_read_config_byte(pdev, SIS_PMR, &tmp);
+ if ((tmp & 0x30)== 0)
+ DPRINTK ("SiS-180/181 pure sata mode detected\n");
+ else
+ DPRINTK ("combined mode detected!\n");
+ }
+ }
+
pci_set_master(pdev);
pci_enable_intx(pdev);

@@ -266,12 +719,12 @@ err_out_regions:
pci_release_regions(pdev);

err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
+ pci_disable_device(pdev);
return rc;

}

+
static int __init sis_init(void)
{
return pci_module_init(&sis_pci_driver);
@@ -284,4 +737,3 @@ static void __exit sis_exit(void)

module_init(sis_init);
module_exit(sis_exit);
-
__END__
### /usr/src/redhat/SOURCES/linux-2.6.12-sata_sis182.patch ###

Please always address to my hardware, os and kernel patching general procedures before posting a question.

Baby steps on kernel patching

Ok it is not really baby steps but here we go:

1. Install the corresponding kernel source, from Fedora RPM, like (I will try to remember to put the URL on every new patch description):

http://download.fedora.redhat.com/pub/fedora/linux/core/updates/3/SRPMS/kernel-2.6.12-1.1381_FC3.src.rpm

2. I assume that you that your kernel source structure will be at: /usr/src/redhat

3. Go to SOURCES and add the files, if you do not trust my scripts

4. Go to SPECS and modify by had the spec file, if you do not trust my patches

5. Apply, or once again do by your own, the patches on the [.config] files

6. Return to SPECS and clean your kernel: rpmbuild --clean

8. Make sure you have enougth disk space (like 2GB) free

7. Generate your kernel: rpmbuild -ba --target=i686

8. Make a coffee or a "chimarrao" because it will take a lot of time

9. Install your new kernel

My OS - 2005.11.05

Ok that the hard one. Please avoid flame. I use a Fedora Core 3 with my own Fedora patched kernel.

Distributions:
Fedora Core 3
Fedora Core 4 (actual one)
Kernel: last one with my patches (can be one or two days later)
glib / glibc: last updated version (can be one or two days later)
Graphical Interface: Gnome
Shell: Bash

Q: Why do you use Fedora?
A: Because I like it (please do not try to convince me to use Debian or Slackware, I just do not want to)
P.S.: Just for the record, I already tryed: FreeBSD, Slackware, Debian and SuSE. Non of them was, on my opinion, as good and easy as RedHat and later Fedora.

Q: What you mean with "my patches"?
A: That's one of the aims of this blog: how do I patched my kernel and why.

Q: Why Gnome?
A: Once again: I just like it :-)
P.S.: Once again just for the record, I once was a WindowMaker fan, after that Enlightment (was really good at the time I used to use it), then changed to KDE and then to Gnone (that I use now).

Q: Have you ever tryed to the "MyMix", that is XYZ?
A: I'm already old enougth to do not spend to much time in front of a computer to try things that I really do not need. I'm like see myself like an old dog: it is really hard to learn new tricks if I still get my "bone" at the end of the day.

My Computer - 2005.11.05

Ok first of all my equipment description, for short: Fujitsu Siemens SCALEO P. But I just like to describe it so here it goes:

Intel(R) Pentium(R) 4 CPU 3.00GHz
1GB - RAM
Radeon X600 (PCIE)
SATA - 180GB
SiS 182 (SATA controler)
SiS 190 (Ethernet controler)
Philips SAA7134 (TV controler)

Q: Why is that important?
A: Because all documentation that here will be posted will address to that equipment, so if you want to apply something from this blog to your case your hardware should be compatible with mine.