Saturday, November 05, 2005

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.

No comments: