diff -Nru a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c --- a/drivers/scsi/ata_piix.c Tue Dec 16 19:48:55 2003 +++ b/drivers/scsi/ata_piix.c Tue Dec 16 19:48:55 2003 @@ -97,6 +97,7 @@ .proc_name = DRV_NAME, .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, }; static struct ata_port_operations piix_pata_ops = { diff -Nru a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c --- a/drivers/scsi/libata-core.c Tue Dec 16 19:48:55 2003 +++ b/drivers/scsi/libata-core.c Tue Dec 16 19:48:55 2003 @@ -1635,8 +1635,8 @@ if (cmd->use_sg) pci_unmap_sg(ap->host_set->pdev, sg, qc->n_elem, dir); else - pci_unmap_single(ap->host_set->pdev, sg[0].dma_address, - sg[0].length, dir); + pci_unmap_single(ap->host_set->pdev, sg_dma_address(&sg[0]), + sg_dma_len(&sg[0]), dir); qc->flags &= ~ATA_QCFLAG_SG; qc->sg = NULL; @@ -1659,8 +1659,8 @@ assert(qc->n_elem > 0); for (i = 0; i < qc->n_elem; i++) { - ap->prd[i].addr = cpu_to_le32(sg[i].dma_address); - ap->prd[i].flags_len = cpu_to_le32(sg[i].length); + ap->prd[i].addr = cpu_to_le32(sg_dma_address(&sg[i])); + ap->prd[i].flags_len = cpu_to_le32(sg_dma_len(&sg[i])); VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", i, le32_to_cpu(ap->prd[i].addr), le32_to_cpu(ap->prd[i].flags_len)); } @@ -1691,12 +1691,12 @@ sg->page = virt_to_page(cmd->request_buffer); sg->offset = (unsigned long) cmd->request_buffer & ~PAGE_MASK; - sg->length = cmd->request_bufflen; + sg_dma_len(sg) = cmd->request_bufflen; if (!have_sg) return 0; - sg->dma_address = pci_map_single(ap->host_set->pdev, + sg_dma_address(sg) = pci_map_single(ap->host_set->pdev, cmd->request_buffer, cmd->request_bufflen, dir); @@ -1917,7 +1917,7 @@ qc->cursg_ofs++; if (cmd->use_sg) - if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg[qc->cursg].length) { + if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) { qc->cursg++; qc->cursg_ofs = 0; } @@ -3224,8 +3224,6 @@ scsi_host_put(ap->host); /* FIXME: check return val */ } - kfree(host_set); - pci_release_regions(pdev); for (i = 0; i < host_set->n_ports; i++) { @@ -3242,6 +3240,7 @@ } } + kfree(host_set); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } @@ -3280,6 +3279,7 @@ return (tmp == bits->val) ? 1 : 0; } + /** * ata_init - * @@ -3305,6 +3305,7 @@ */ EXPORT_SYMBOL_GPL(pci_test_config_bits); +EXPORT_SYMBOL_GPL(ata_std_bios_param); EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_device_add); EXPORT_SYMBOL_GPL(ata_qc_complete); diff -Nru a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c --- a/drivers/scsi/libata-scsi.c Tue Dec 16 19:48:55 2003 +++ b/drivers/scsi/libata-scsi.c Tue Dec 16 19:48:55 2003 @@ -32,6 +32,29 @@ #include "libata.h" + +/** + * ata_std_bios_param - generic bios head/sector/cylinder calculator + * used by sd. Most BIOSes nowadays expect a XXX/255/16 (CHS) + * mapping. Some situations may arise where the disk is not + * bootable if this is not used. + * + * LOCKING: + * + * RETURNS: + * + */ +int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, + sector_t capacity, int geom[]) +{ + geom[0] = 255; + geom[1] = 63; + geom[2] = capacity / (geom[0] * geom[1]); + + return 0; +} + + struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap, struct ata_device *dev, Scsi_Cmnd *cmd, diff -Nru a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c --- a/drivers/scsi/sata_promise.c Tue Dec 16 19:48:55 2003 +++ b/drivers/scsi/sata_promise.c Tue Dec 16 19:48:55 2003 @@ -34,10 +34,8 @@ #include #include -#undef DIRECT_HDMA - #define DRV_NAME "sata_promise" -#define DRV_VERSION "0.86" +#define DRV_VERSION "0.88" enum { @@ -82,6 +80,42 @@ PDC_FLAG_20621 = (1 << 30), /* we have a 20621 */ PDC_HDMA_RESET = (1 << 11), /* HDMA reset */ + + PDC_MAX_HDMA = 32, + PDC_HDMA_Q_MASK = (PDC_MAX_HDMA - 1), + + PDC_DIMM0_SPD_DEV_ADDRESS = 0x50, + PDC_DIMM1_SPD_DEV_ADDRESS = 0x51, + PDC_MAX_DIMM_MODULE = 0x02, + PDC_I2C_CONTROL_OFFSET = 0x48, + PDC_I2C_ADDR_DATA_OFFSET = 0x4C, + PDC_DIMM0_CONTROL_OFFSET = 0x80, + PDC_DIMM1_CONTROL_OFFSET = 0x84, + PDC_SDRAM_CONTROL_OFFSET = 0x88, + PDC_I2C_WRITE = 0x00000000, + PDC_I2C_READ = 0x00000040, + PDC_I2C_START = 0x00000080, + PDC_I2C_MASK_INT = 0x00000020, + PDC_I2C_COMPLETE = 0x00010000, + PDC_I2C_NO_ACK = 0x00100000, + PDC_DIMM_SPD_SUBADDRESS_START = 0x00, + PDC_DIMM_SPD_SUBADDRESS_END = 0x7F, + PDC_DIMM_SPD_ROW_NUM = 3, + PDC_DIMM_SPD_COLUMN_NUM = 4, + PDC_DIMM_SPD_MODULE_ROW = 5, + PDC_DIMM_SPD_TYPE = 11, + PDC_DIMM_SPD_FRESH_RATE = 12, + PDC_DIMM_SPD_BANK_NUM = 17, + PDC_DIMM_SPD_CAS_LATENCY = 18, + PDC_DIMM_SPD_ATTRIBUTE = 21, + PDC_DIMM_SPD_ROW_PRE_CHARGE = 27, + PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28, + PDC_DIMM_SPD_RAS_CAS_DELAY = 29, + PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30, + PDC_DIMM_SPD_SYSTEM_FREQ = 126, + PDC_CTL_STATUS = 0x08, + PDC_DIMM_WINDOW_CTLR = 0x0C, + PDC_GENERAL_CTLR = 0x484, }; @@ -89,6 +123,15 @@ u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512]; u8 *pkt; dma_addr_t pkt_dma; + + unsigned int doing_hdma; + unsigned int hdma_prod; + unsigned int hdma_cons; + struct { + struct ata_queued_cmd *qc; + unsigned int seq; + unsigned long pkt_ofs; + } hdma[32]; }; @@ -114,6 +157,18 @@ static void pdc20621_host_stop(struct ata_host_set *host_set); static inline void pdc_dma_complete (struct ata_port *ap, struct ata_queued_cmd *qc); +static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe); +static int pdc20621_detect_dimm(struct ata_probe_ent *pe); +static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, + u32 device, u32 subaddr, u32 *pdata); +static int pdc20621_prog_dimm0(struct ata_probe_ent *pe); +static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe); +#ifdef ATA_VERBOSE_DEBUG +static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, + void *psource, u32 offset, u32 size); +#endif +static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, + void *psource, u32 offset, u32 size); static Scsi_Host_Template pdc_sata_sht = { @@ -131,6 +186,7 @@ .proc_name = DRV_NAME, .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, }; static struct ata_port_operations pdc_sata_ops = { @@ -256,6 +312,7 @@ rc = -ENOMEM; goto err_out; } + memset(pp, 0, sizeof(*pp)); pp->pkt = pci_alloc_consistent(pdev, 128, &pp->pkt_dma); if (!pp->pkt) { @@ -605,8 +662,8 @@ last = qc->n_elem; idx = 0; for (i = 0; i < last; i++) { - buf[idx++] = cpu_to_le32(sg[i].dma_address); - buf[idx++] = cpu_to_le32(sg[i].length); + buf[idx++] = cpu_to_le32(sg_dma_address(&sg[i])); + buf[idx++] = cpu_to_le32(sg_dma_len(&sg[i])); total_len += sg[i].length; } buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT); @@ -643,42 +700,60 @@ VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len); } -#ifdef DIRECT_HDMA -static void pdc20621_push_hdma(struct ata_queued_cmd *qc) +static void __pdc20621_push_hdma(struct ata_queued_cmd *qc, + unsigned int seq, + u32 pkt_ofs) { struct ata_port *ap = qc->ap; struct ata_host_set *host_set = ap->host_set; - unsigned int port_no = ap->port_no; void *mmio = host_set->mmio_base; - unsigned int rw = (qc->flags & ATA_QCFLAG_WRITE); - u32 tmp; - - unsigned int host_sg = PDC_20621_DIMM_BASE + - (PDC_DIMM_WINDOW_STEP * port_no) + - PDC_DIMM_HOST_PRD; - unsigned int dimm_sg = PDC_20621_DIMM_BASE + - (PDC_DIMM_WINDOW_STEP * port_no) + - PDC_DIMM_HPKT_PRD; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; - tmp = readl(mmio + PDC_HDMA_CTLSTAT) & 0xffffff00; - tmp |= port_no + 1 + 4; /* seq. ID */ - if (!rw) - tmp |= (1 << 6); /* hdma data direction */ - writel(tmp, mmio + PDC_HDMA_CTLSTAT); /* note: stops DMA, if active */ - readl(mmio + PDC_HDMA_CTLSTAT); /* flush */ - - writel(host_sg, mmio + 0x108); - writel(dimm_sg, mmio + 0x10C); - writel(0, mmio + 0x128); + writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4)); + readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */ - tmp |= (1 << 7); - writel(tmp, mmio + PDC_HDMA_CTLSTAT); - readl(mmio + PDC_HDMA_CTLSTAT); /* flush */ + writel(pkt_ofs, mmio + PDC_HDMA_PKT_SUBMIT); + readl(mmio + PDC_HDMA_PKT_SUBMIT); /* flush */ +} + +static void pdc20621_push_hdma(struct ata_queued_cmd *qc, + unsigned int seq, + u32 pkt_ofs) +{ + struct ata_port *ap = qc->ap; + struct pdc_port_priv *pp = ap->private_data; + unsigned int idx = pp->hdma_prod & PDC_HDMA_Q_MASK; + + if (!pp->doing_hdma) { + __pdc20621_push_hdma(qc, seq, pkt_ofs); + pp->doing_hdma = 1; + return; + } + + pp->hdma[idx].qc = qc; + pp->hdma[idx].seq = seq; + pp->hdma[idx].pkt_ofs = pkt_ofs; + pp->hdma_prod++; +} + +static void pdc20621_pop_hdma(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pdc_port_priv *pp = ap->private_data; + unsigned int idx = pp->hdma_cons & PDC_HDMA_Q_MASK; + + /* if nothing on queue, we're done */ + if (pp->hdma_prod == pp->hdma_cons) { + pp->doing_hdma = 0; + return; + } + + __pdc20621_push_hdma(pp->hdma[idx].qc, pp->hdma[idx].seq, + pp->hdma[idx].pkt_ofs); + pp->hdma_cons++; } -#endif #ifdef ATA_VERBOSE_DEBUG static void pdc20621_dump_hdma(struct ata_queued_cmd *qc) @@ -724,23 +799,17 @@ wmb(); /* flush PRD, pkt writes */ - writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4)); - readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */ - if (doing_hdma) { pdc20621_dump_hdma(qc); -#ifdef DIRECT_HDMA - pdc20621_push_hdma(qc); -#else - writel(port_ofs + PDC_DIMM_HOST_PKT, - mmio + PDC_HDMA_PKT_SUBMIT); - readl(mmio + PDC_HDMA_PKT_SUBMIT); /* flush */ -#endif - VPRINTK("submitted ofs 0x%x (%u), seq %u\n", - port_ofs + PDC_DIMM_HOST_PKT, - port_ofs + PDC_DIMM_HOST_PKT, - seq); + pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT); + VPRINTK("queued ofs 0x%x (%u), seq %u\n", + port_ofs + PDC_DIMM_HOST_PKT, + port_ofs + PDC_DIMM_HOST_PKT, + seq); } else { + writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4)); + readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */ + writel(port_ofs + PDC_DIMM_ATA_PKT, (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); @@ -771,6 +840,7 @@ VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); pdc_dma_complete(ap, qc); + pdc20621_pop_hdma(qc); } /* step one - exec ATA command */ @@ -781,15 +851,8 @@ /* submit hdma pkt */ pdc20621_dump_hdma(qc); - writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4)); - readl(mmio + PDC_20621_SEQCTL + (seq * 4)); -#ifdef DIRECT_HDMA - pdc20621_push_hdma(qc); -#else - writel(port_ofs + PDC_DIMM_HOST_PKT, - mmio + PDC_HDMA_PKT_SUBMIT); - readl(mmio + PDC_HDMA_PKT_SUBMIT); -#endif + pdc20621_push_hdma(qc, seq, + port_ofs + PDC_DIMM_HOST_PKT); } handled = 1; break; @@ -814,6 +877,7 @@ VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); pdc_dma_complete(ap, qc); + pdc20621_pop_hdma(qc); } handled = 1; break; @@ -1098,11 +1162,371 @@ port->ctl_addr = base + 0x38; } + +#ifdef ATA_VERBOSE_DEBUG +static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, + u32 offset, u32 size) +{ + u32 window_size; + u16 idx; + u8 page_mask; + long dist; + void *mmio = pe->mmio_base; + void *dimm_mmio = pe->private_data; + + /* hard-code chip #0 */ + mmio += PDC_CHIP0_OFS; + + page_mask = 0x00; + window_size = 0x2000 * 4; /* 32K byte uchar size */ + idx = (u16) (offset / window_size); + + writel(0x01, mmio + PDC_GENERAL_CTLR); + readl(mmio + PDC_GENERAL_CTLR); + writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); + readl(mmio + PDC_DIMM_WINDOW_CTLR); + + offset -= (idx * window_size); + idx++; + dist = ((long) (window_size - (offset + size))) >= 0 ? size : + (long) (window_size - offset); + memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4), + dist); + + psource += dist; + size -= dist; + for (; (long) size >= (long) window_size ;) { + writel(0x01, mmio + PDC_GENERAL_CTLR); + readl(mmio + PDC_GENERAL_CTLR); + writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); + readl(mmio + PDC_DIMM_WINDOW_CTLR); + memcpy_fromio((char *) psource, (char *) (dimm_mmio), + window_size / 4); + psource += window_size; + size -= window_size; + idx ++; + } + + if (size) { + writel(0x01, mmio + PDC_GENERAL_CTLR); + readl(mmio + PDC_GENERAL_CTLR); + writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); + readl(mmio + PDC_DIMM_WINDOW_CTLR); + memcpy_fromio((char *) psource, (char *) (dimm_mmio), + size / 4); + } +} +#endif + + +static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, + u32 offset, u32 size) +{ + u32 window_size; + u16 idx; + u8 page_mask; + long dist; + void *mmio = pe->mmio_base; + void *dimm_mmio = pe->private_data; + + /* hard-code chip #0 */ + mmio += PDC_CHIP0_OFS; + + page_mask = 0x00; + window_size = 0x2000 * 4; /* 32K byte uchar size */ + idx = (u16) (offset / window_size); + + writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); + readl(mmio + PDC_DIMM_WINDOW_CTLR); + offset -= (idx * window_size); + idx++; + dist = ((long) (window_size - (offset + size))) >= 0 ? size : + (long) (window_size - offset); + memcpy_toio((char *) (dimm_mmio + offset / 4), (char *) psource, dist); + writel(0x01, mmio + PDC_GENERAL_CTLR); + readl(mmio + PDC_GENERAL_CTLR); + + psource += dist; + size -= dist; + for (; (long) size >= (long) window_size ;) { + writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); + readl(mmio + PDC_DIMM_WINDOW_CTLR); + memcpy_toio((char *) (dimm_mmio), (char *) psource, + window_size / 4); + writel(0x01, mmio + PDC_GENERAL_CTLR); + readl(mmio + PDC_GENERAL_CTLR); + psource += window_size; + size -= window_size; + idx ++; + } + + if (size) { + writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); + readl(mmio + PDC_DIMM_WINDOW_CTLR); + memcpy_toio((char *) (dimm_mmio), (char *) psource, size / 4); + writel(0x01, mmio + PDC_GENERAL_CTLR); + readl(mmio + PDC_GENERAL_CTLR); + } +} + + +static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, + u32 subaddr, u32 *pdata) +{ + void *mmio = pe->mmio_base; + u32 i2creg = 0; + u32 status; + u32 count =0; + + /* hard-code chip #0 */ + mmio += PDC_CHIP0_OFS; + + i2creg |= device << 24; + i2creg |= subaddr << 16; + + /* Set the device and subaddress */ + writel(i2creg, mmio + PDC_I2C_ADDR_DATA_OFFSET); + readl(mmio + PDC_I2C_ADDR_DATA_OFFSET); + + /* Write Control to perform read operation, mask int */ + writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT, + mmio + PDC_I2C_CONTROL_OFFSET); + + for (count = 0; count <= 1000; count ++) { + status = readl(mmio + PDC_I2C_CONTROL_OFFSET); + if (status & PDC_I2C_COMPLETE) { + status = readl(mmio + PDC_I2C_ADDR_DATA_OFFSET); + break; + } else if (count == 1000) + return 0; + } + + *pdata = (status >> 8) & 0x000000ff; + return 1; +} + + +static int pdc20621_detect_dimm(struct ata_probe_ent *pe) +{ + u32 data=0 ; + if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, + PDC_DIMM_SPD_SYSTEM_FREQ, &data)) { + if (data == 100) + return 100; + } else + return 0; + + if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) { + if(data <= 0x75) + return 133; + } else + return 0; + + return 0; +} + + +static int pdc20621_prog_dimm0(struct ata_probe_ent *pe) +{ + u32 spd0[50]; + u32 data = 0; + int size, i; + u8 bdimmsize; + void *mmio = pe->mmio_base; + static const struct { + unsigned int reg; + unsigned int ofs; + } pdc_i2c_read_data [] = { + { PDC_DIMM_SPD_TYPE, 11 }, + { PDC_DIMM_SPD_FRESH_RATE, 12 }, + { PDC_DIMM_SPD_COLUMN_NUM, 4 }, + { PDC_DIMM_SPD_ATTRIBUTE, 21 }, + { PDC_DIMM_SPD_ROW_NUM, 3 }, + { PDC_DIMM_SPD_BANK_NUM, 17 }, + { PDC_DIMM_SPD_MODULE_ROW, 5 }, + { PDC_DIMM_SPD_ROW_PRE_CHARGE, 27 }, + { PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 }, + { PDC_DIMM_SPD_RAS_CAS_DELAY, 29 }, + { PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 }, + { PDC_DIMM_SPD_CAS_LATENCY, 18 }, + }; + + /* hard-code chip #0 */ + mmio += PDC_CHIP0_OFS; + + for(i=0; i spd0[28]) + ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10; + data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12; + + if (spd0[18] & 0x08) + data |= ((0x03) << 14); + else if (spd0[18] & 0x04) + data |= ((0x02) << 14); + else if (spd0[18] & 0x01) + data |= ((0x01) << 14); + else + data |= (0 << 14); + + /* + Calculate the size of bDIMMSize (power of 2) and + merge the DIMM size by program start/end address. + */ + + bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3; + size = (1 << bdimmsize) >> 20; /* size = xxx(MB) */ + data |= (((size / 16) - 1) << 16); + data |= (0 << 23); + data |= 8; + writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET); + readl(mmio + PDC_DIMM0_CONTROL_OFFSET); + return size; +} + + +static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe) +{ + u32 data, spd0; + int error, i; + void *mmio = pe->mmio_base; + + /* hard-code chip #0 */ + mmio += PDC_CHIP0_OFS; + + /* + Set To Default : DIMM Module Global Control Register (0x022259F1) + DIMM Arbitration Disable (bit 20) + DIMM Data/Control Output Driving Selection (bit12 - bit15) + Refresh Enable (bit 17) + */ + + data = 0x022259F1; + writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET); + readl(mmio + PDC_SDRAM_CONTROL_OFFSET); + + /* Turn on for ECC */ + pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, + PDC_DIMM_SPD_TYPE, &spd0); + if (spd0 == 0x02) { + data |= (0x01 << 16); + writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET); + readl(mmio + PDC_SDRAM_CONTROL_OFFSET); + printk(KERN_ERR "Local DIMM ECC Enabled\n"); + } + + /* DIMM Initialization Select/Enable (bit 18/19) */ + data &= (~(1<<18)); + data |= (1<<19); + writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET); + + error = 1; + for (i = 1; i <= 10; i++) { /* polling ~5 secs */ + data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET); + if (!(data & (1<<19))) { + error = 0; + break; + } + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((i * 100) * HZ / 1000); + } + return error; +} + + +static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe) +{ + int speed, size, length; + u32 addr,spd0,pci_status; + u32 tmp=0; + void *mmio = pe->mmio_base; + + /* hard-code chip #0 */ + mmio += PDC_CHIP0_OFS; + + /* Initialize PLL. */ + pci_status = 0x8a531824; + writel(pci_status, mmio + PDC_CTL_STATUS); + readl(mmio + PDC_CTL_STATUS); + + /* + Read SPD of DIMM by I2C interface, + and program the DIMM Module Controller. + */ + if (!(speed = pdc20621_detect_dimm(pe))) { + printk(KERN_ERR "Detect Local DIMM Fail\n"); + return 1; /* DIMM error */ + } + VPRINTK("Local DIMM Speed = %d\n", speed); + + /* Programming DIMM0 Module Control Register (index_CID0:80h) */ + size = pdc20621_prog_dimm0(pe); + VPRINTK("Local DIMM Size = %dMB\n",size); + + /* Programming DIMM Module Global Control Register (index_CID0:88h) */ + if (pdc20621_prog_dimm_global(pe)) { + printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n"); + return 1; + } + +#ifdef ATA_VERBOSE_DEBUG + { + u8 test_parttern1[40] = {0x55,0xAA,'P','r','o','m','i','s','e',' ', + 'N','o','t',' ','Y','e','t',' ','D','e','f','i','n','e','d',' ', + '1','.','1','0', + '9','8','0','3','1','6','1','2',0,0}; + u8 test_parttern2[40] = {0}; + + pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40); + pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40); + + pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40); + pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40); + printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], + test_parttern2[1], &(test_parttern2[2])); + pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040, + 40); + printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], + test_parttern2[1], &(test_parttern2[2])); + + pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40); + pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40); + printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], + test_parttern2[1], &(test_parttern2[2])); + } +#endif + + /* ECC initiliazation. */ + + pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, + PDC_DIMM_SPD_TYPE, &spd0); + if (spd0 == 0x02) { + VPRINTK("Start ECC initialization\n"); + addr = 0; + length = size * 1024 * 1024; + while (addr < length) { + pdc20621_put_to_dimm(pe, (void *) &tmp, addr, + sizeof(u32)); + addr += sizeof(u32); + } + VPRINTK("Finish ECC initialization\n"); + } + return 0; +} + + static void pdc_20621_init(struct ata_probe_ent *pe) { u32 tmp; void *mmio = pe->mmio_base; + /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; /* @@ -1268,9 +1692,14 @@ pci_set_master(pdev); /* initialize adapter */ - if (have_20621) + if (have_20621) { + /* initialize local dimm */ + if (pdc20621_dimm_init(probe_ent)) { + rc = -ENOMEM; + goto err_out_iounmap; + } pdc_20621_init(probe_ent); - else + } else pdc_host_init(board_idx, probe_ent); /* FIXME: check ata_device_add return value */ diff -Nru a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c --- a/drivers/scsi/sata_sil.c Tue Dec 16 19:48:55 2003 +++ b/drivers/scsi/sata_sil.c Tue Dec 16 19:48:55 2003 @@ -87,6 +87,7 @@ .proc_name = DRV_NAME, .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, }; static struct ata_port_operations sil_ops = { diff -Nru a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c --- a/drivers/scsi/sata_svw.c Tue Dec 16 19:48:55 2003 +++ b/drivers/scsi/sata_svw.c Tue Dec 16 19:48:55 2003 @@ -219,6 +219,7 @@ #ifdef CONFIG_ALL_PPC .proc_info = k2_sata_proc_info #endif + .bios_param = ata_std_bios_param, }; diff -Nru a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c --- a/drivers/scsi/sata_via.c Tue Dec 16 19:48:55 2003 +++ b/drivers/scsi/sata_via.c Tue Dec 16 19:48:55 2003 @@ -78,6 +78,7 @@ .proc_name = DRV_NAME, .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, }; static struct ata_port_operations svia_sata_ops = { diff -Nru a/include/linux/libata.h b/include/linux/libata.h --- a/include/linux/libata.h Tue Dec 16 19:48:55 2003 +++ b/include/linux/libata.h Tue Dec 16 19:48:55 2003 @@ -28,6 +28,7 @@ #include #include + /* * compile-time options */ @@ -171,6 +172,7 @@ }; /* forward declarations */ +struct scsi_device; struct ata_port_operations; struct ata_port; struct ata_queued_cmd; @@ -427,6 +429,9 @@ extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits); extern void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat, unsigned int done_late); extern void ata_eng_timeout(struct ata_port *ap); +extern int ata_std_bios_param(struct scsi_device *sdev, + struct block_device *bdev, + sector_t capacity, int geom[]); static inline unsigned long msecs_to_jiffies(unsigned long msecs)