|
@@ -2,6 +2,7 @@
|
|
* sata_promise.c - Promise SATA
|
|
* sata_promise.c - Promise SATA
|
|
*
|
|
*
|
|
* Maintained by: Jeff Garzik <jgarzik@pobox.com>
|
|
* Maintained by: Jeff Garzik <jgarzik@pobox.com>
|
|
|
|
+ * Mikael Pettersson <mikpe@it.uu.se>
|
|
* Please ALWAYS copy linux-ide@vger.kernel.org
|
|
* Please ALWAYS copy linux-ide@vger.kernel.org
|
|
* on emails.
|
|
* on emails.
|
|
*
|
|
*
|
|
@@ -45,11 +46,12 @@
|
|
#include "sata_promise.h"
|
|
#include "sata_promise.h"
|
|
|
|
|
|
#define DRV_NAME "sata_promise"
|
|
#define DRV_NAME "sata_promise"
|
|
-#define DRV_VERSION "2.10"
|
|
|
|
|
|
+#define DRV_VERSION "2.11"
|
|
|
|
|
|
enum {
|
|
enum {
|
|
PDC_MAX_PORTS = 4,
|
|
PDC_MAX_PORTS = 4,
|
|
PDC_MMIO_BAR = 3,
|
|
PDC_MMIO_BAR = 3,
|
|
|
|
+ PDC_MAX_PRD = LIBATA_MAX_PRD - 1, /* -1 for ASIC PRD bug workaround */
|
|
|
|
|
|
/* register offsets */
|
|
/* register offsets */
|
|
PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */
|
|
PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */
|
|
@@ -157,7 +159,7 @@ static struct scsi_host_template pdc_ata_sht = {
|
|
.queuecommand = ata_scsi_queuecmd,
|
|
.queuecommand = ata_scsi_queuecmd,
|
|
.can_queue = ATA_DEF_QUEUE,
|
|
.can_queue = ATA_DEF_QUEUE,
|
|
.this_id = ATA_SHT_THIS_ID,
|
|
.this_id = ATA_SHT_THIS_ID,
|
|
- .sg_tablesize = LIBATA_MAX_PRD,
|
|
|
|
|
|
+ .sg_tablesize = PDC_MAX_PRD,
|
|
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
|
|
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
|
|
.emulated = ATA_SHT_EMULATED,
|
|
.emulated = ATA_SHT_EMULATED,
|
|
.use_clustering = ATA_SHT_USE_CLUSTERING,
|
|
.use_clustering = ATA_SHT_USE_CLUSTERING,
|
|
@@ -240,7 +242,7 @@ static const struct ata_port_operations pdc_pata_ops = {
|
|
};
|
|
};
|
|
|
|
|
|
static const struct ata_port_info pdc_port_info[] = {
|
|
static const struct ata_port_info pdc_port_info[] = {
|
|
- /* board_2037x */
|
|
|
|
|
|
+ [board_2037x] =
|
|
{
|
|
{
|
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
|
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
|
|
PDC_FLAG_SATA_PATA,
|
|
PDC_FLAG_SATA_PATA,
|
|
@@ -250,7 +252,7 @@ static const struct ata_port_info pdc_port_info[] = {
|
|
.port_ops = &pdc_old_sata_ops,
|
|
.port_ops = &pdc_old_sata_ops,
|
|
},
|
|
},
|
|
|
|
|
|
- /* board_2037x_pata */
|
|
|
|
|
|
+ [board_2037x_pata] =
|
|
{
|
|
{
|
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
|
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
|
|
.pio_mask = 0x1f, /* pio0-4 */
|
|
.pio_mask = 0x1f, /* pio0-4 */
|
|
@@ -259,7 +261,7 @@ static const struct ata_port_info pdc_port_info[] = {
|
|
.port_ops = &pdc_pata_ops,
|
|
.port_ops = &pdc_pata_ops,
|
|
},
|
|
},
|
|
|
|
|
|
- /* board_20319 */
|
|
|
|
|
|
+ [board_20319] =
|
|
{
|
|
{
|
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
|
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
|
|
PDC_FLAG_4_PORTS,
|
|
PDC_FLAG_4_PORTS,
|
|
@@ -269,7 +271,7 @@ static const struct ata_port_info pdc_port_info[] = {
|
|
.port_ops = &pdc_old_sata_ops,
|
|
.port_ops = &pdc_old_sata_ops,
|
|
},
|
|
},
|
|
|
|
|
|
- /* board_20619 */
|
|
|
|
|
|
+ [board_20619] =
|
|
{
|
|
{
|
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
|
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
|
|
PDC_FLAG_4_PORTS,
|
|
PDC_FLAG_4_PORTS,
|
|
@@ -279,7 +281,7 @@ static const struct ata_port_info pdc_port_info[] = {
|
|
.port_ops = &pdc_pata_ops,
|
|
.port_ops = &pdc_pata_ops,
|
|
},
|
|
},
|
|
|
|
|
|
- /* board_2057x */
|
|
|
|
|
|
+ [board_2057x] =
|
|
{
|
|
{
|
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
|
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
|
|
PDC_FLAG_GEN_II | PDC_FLAG_SATA_PATA,
|
|
PDC_FLAG_GEN_II | PDC_FLAG_SATA_PATA,
|
|
@@ -289,7 +291,7 @@ static const struct ata_port_info pdc_port_info[] = {
|
|
.port_ops = &pdc_sata_ops,
|
|
.port_ops = &pdc_sata_ops,
|
|
},
|
|
},
|
|
|
|
|
|
- /* board_2057x_pata */
|
|
|
|
|
|
+ [board_2057x_pata] =
|
|
{
|
|
{
|
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
|
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
|
|
PDC_FLAG_GEN_II,
|
|
PDC_FLAG_GEN_II,
|
|
@@ -299,7 +301,7 @@ static const struct ata_port_info pdc_port_info[] = {
|
|
.port_ops = &pdc_pata_ops,
|
|
.port_ops = &pdc_pata_ops,
|
|
},
|
|
},
|
|
|
|
|
|
- /* board_40518 */
|
|
|
|
|
|
+ [board_40518] =
|
|
{
|
|
{
|
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
|
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
|
|
PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS,
|
|
PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS,
|
|
@@ -523,6 +525,84 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
|
|
memcpy(buf+31, cdb, cdb_len);
|
|
memcpy(buf+31, cdb, cdb_len);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * pdc_fill_sg - Fill PCI IDE PRD table
|
|
|
|
+ * @qc: Metadata associated with taskfile to be transferred
|
|
|
|
+ *
|
|
|
|
+ * Fill PCI IDE PRD (scatter-gather) table with segments
|
|
|
|
+ * associated with the current disk command.
|
|
|
|
+ * Make sure hardware does not choke on it.
|
|
|
|
+ *
|
|
|
|
+ * LOCKING:
|
|
|
|
+ * spin_lock_irqsave(host lock)
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+static void pdc_fill_sg(struct ata_queued_cmd *qc)
|
|
|
|
+{
|
|
|
|
+ struct ata_port *ap = qc->ap;
|
|
|
|
+ struct scatterlist *sg;
|
|
|
|
+ unsigned int idx;
|
|
|
|
+ const u32 SG_COUNT_ASIC_BUG = 41*4;
|
|
|
|
+
|
|
|
|
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ WARN_ON(qc->__sg == NULL);
|
|
|
|
+ WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
|
|
|
|
+
|
|
|
|
+ idx = 0;
|
|
|
|
+ ata_for_each_sg(sg, qc) {
|
|
|
|
+ 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) {
|
|
|
|
+ u32 len = le32_to_cpu(ap->prd[idx - 1].flags_len);
|
|
|
|
+
|
|
|
|
+ if (len > SG_COUNT_ASIC_BUG) {
|
|
|
|
+ u32 addr;
|
|
|
|
+
|
|
|
|
+ VPRINTK("Splitting last PRD.\n");
|
|
|
|
+
|
|
|
|
+ addr = le32_to_cpu(ap->prd[idx - 1].addr);
|
|
|
|
+ ap->prd[idx - 1].flags_len -= cpu_to_le32(SG_COUNT_ASIC_BUG);
|
|
|
|
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG);
|
|
|
|
+
|
|
|
|
+ addr = addr + len - SG_COUNT_ASIC_BUG;
|
|
|
|
+ len = SG_COUNT_ASIC_BUG;
|
|
|
|
+ ap->prd[idx].addr = cpu_to_le32(addr);
|
|
|
|
+ ap->prd[idx].flags_len = cpu_to_le32(len);
|
|
|
|
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
|
|
|
|
+
|
|
|
|
+ idx++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
static void pdc_qc_prep(struct ata_queued_cmd *qc)
|
|
static void pdc_qc_prep(struct ata_queued_cmd *qc)
|
|
{
|
|
{
|
|
struct pdc_port_priv *pp = qc->ap->private_data;
|
|
struct pdc_port_priv *pp = qc->ap->private_data;
|
|
@@ -532,7 +612,7 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc)
|
|
|
|
|
|
switch (qc->tf.protocol) {
|
|
switch (qc->tf.protocol) {
|
|
case ATA_PROT_DMA:
|
|
case ATA_PROT_DMA:
|
|
- ata_qc_prep(qc);
|
|
|
|
|
|
+ pdc_fill_sg(qc);
|
|
/* fall through */
|
|
/* fall through */
|
|
|
|
|
|
case ATA_PROT_NODATA:
|
|
case ATA_PROT_NODATA:
|
|
@@ -548,11 +628,11 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc)
|
|
break;
|
|
break;
|
|
|
|
|
|
case ATA_PROT_ATAPI:
|
|
case ATA_PROT_ATAPI:
|
|
- ata_qc_prep(qc);
|
|
|
|
|
|
+ pdc_fill_sg(qc);
|
|
break;
|
|
break;
|
|
|
|
|
|
case ATA_PROT_ATAPI_DMA:
|
|
case ATA_PROT_ATAPI_DMA:
|
|
- ata_qc_prep(qc);
|
|
|
|
|
|
+ pdc_fill_sg(qc);
|
|
/*FALLTHROUGH*/
|
|
/*FALLTHROUGH*/
|
|
case ATA_PROT_ATAPI_NODATA:
|
|
case ATA_PROT_ATAPI_NODATA:
|
|
pdc_atapi_pkt(qc);
|
|
pdc_atapi_pkt(qc);
|