diff options
Diffstat (limited to 'drivers/ata/sata_promise.c')
-rw-r--r-- | drivers/ata/sata_promise.c | 215 |
1 files changed, 112 insertions, 103 deletions
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index f251a5f569d..5a10dc5048a 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -46,7 +46,7 @@ #include "sata_promise.h" #define DRV_NAME "sata_promise" -#define DRV_VERSION "2.11" +#define DRV_VERSION "2.12" enum { PDC_MAX_PORTS = 4, @@ -143,101 +143,57 @@ static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile static int pdc_check_atapi_dma(struct ata_queued_cmd *qc); static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc); static void pdc_irq_clear(struct ata_port *ap); -static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc); +static unsigned int pdc_qc_issue(struct ata_queued_cmd *qc); static void pdc_freeze(struct ata_port *ap); +static void pdc_sata_freeze(struct ata_port *ap); static void pdc_thaw(struct ata_port *ap); -static void pdc_pata_error_handler(struct ata_port *ap); -static void pdc_sata_error_handler(struct ata_port *ap); +static void pdc_sata_thaw(struct ata_port *ap); +static void pdc_error_handler(struct ata_port *ap); static void pdc_post_internal_cmd(struct ata_queued_cmd *qc); static int pdc_pata_cable_detect(struct ata_port *ap); static int pdc_sata_cable_detect(struct ata_port *ap); static struct scsi_host_template pdc_ata_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, + ATA_BASE_SHT(DRV_NAME), .sg_tablesize = PDC_MAX_PRD, - .cmd_per_lun = ATA_SHT_CMD_PER_LUN, - .emulated = ATA_SHT_EMULATED, - .use_clustering = ATA_SHT_USE_CLUSTERING, - .proc_name = DRV_NAME, .dma_boundary = ATA_DMA_BOUNDARY, - .slave_configure = ata_scsi_slave_config, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, }; -static const struct ata_port_operations pdc_sata_ops = { - .tf_load = pdc_tf_load_mmio, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = pdc_exec_command_mmio, - .dev_select = ata_std_dev_select, - .check_atapi_dma = pdc_check_atapi_dma, +static const struct ata_port_operations pdc_common_ops = { + .inherits = &ata_sff_port_ops, + .sff_tf_load = pdc_tf_load_mmio, + .sff_exec_command = pdc_exec_command_mmio, + .check_atapi_dma = pdc_check_atapi_dma, .qc_prep = pdc_qc_prep, - .qc_issue = pdc_qc_issue_prot, - .freeze = pdc_freeze, - .thaw = pdc_thaw, - .error_handler = pdc_sata_error_handler, + .qc_issue = pdc_qc_issue, + .sff_irq_clear = pdc_irq_clear, + .post_internal_cmd = pdc_post_internal_cmd, - .cable_detect = pdc_sata_cable_detect, - .data_xfer = ata_data_xfer, - .irq_clear = pdc_irq_clear, - .irq_on = ata_irq_on, + .error_handler = pdc_error_handler, +}; +static struct ata_port_operations pdc_sata_ops = { + .inherits = &pdc_common_ops, + .cable_detect = pdc_sata_cable_detect, + .freeze = pdc_sata_freeze, + .thaw = pdc_sata_thaw, .scr_read = pdc_sata_scr_read, .scr_write = pdc_sata_scr_write, .port_start = pdc_sata_port_start, }; /* First-generation chips need a more restrictive ->check_atapi_dma op */ -static const struct ata_port_operations pdc_old_sata_ops = { - .tf_load = pdc_tf_load_mmio, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = pdc_exec_command_mmio, - .dev_select = ata_std_dev_select, +static struct ata_port_operations pdc_old_sata_ops = { + .inherits = &pdc_sata_ops, .check_atapi_dma = pdc_old_sata_check_atapi_dma, - - .qc_prep = pdc_qc_prep, - .qc_issue = pdc_qc_issue_prot, - .freeze = pdc_freeze, - .thaw = pdc_thaw, - .error_handler = pdc_sata_error_handler, - .post_internal_cmd = pdc_post_internal_cmd, - .cable_detect = pdc_sata_cable_detect, - .data_xfer = ata_data_xfer, - .irq_clear = pdc_irq_clear, - .irq_on = ata_irq_on, - - .scr_read = pdc_sata_scr_read, - .scr_write = pdc_sata_scr_write, - .port_start = pdc_sata_port_start, }; -static const struct ata_port_operations pdc_pata_ops = { - .tf_load = pdc_tf_load_mmio, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = pdc_exec_command_mmio, - .dev_select = ata_std_dev_select, - .check_atapi_dma = pdc_check_atapi_dma, - - .qc_prep = pdc_qc_prep, - .qc_issue = pdc_qc_issue_prot, +static struct ata_port_operations pdc_pata_ops = { + .inherits = &pdc_common_ops, + .cable_detect = pdc_pata_cable_detect, .freeze = pdc_freeze, .thaw = pdc_thaw, - .error_handler = pdc_pata_error_handler, - .post_internal_cmd = pdc_post_internal_cmd, - .cable_detect = pdc_pata_cable_detect, - .data_xfer = ata_data_xfer, - .irq_clear = pdc_irq_clear, - .irq_on = ata_irq_on, - .port_start = pdc_common_port_start, }; @@ -449,7 +405,7 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc) u8 *cdb = qc->cdb; struct pdc_port_priv *pp = ap->private_data; u8 *buf = pp->pkt; - u32 *buf32 = (u32 *) buf; + __le32 *buf32 = (__le32 *) buf; unsigned int dev_sel, feature; /* set control bits (byte 0), zero delay seq id (byte 3), @@ -631,6 +587,41 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc) } } +static int pdc_is_sataii_tx4(unsigned long flags) +{ + const unsigned long mask = PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS; + return (flags & mask) == mask; +} + +static unsigned int pdc_port_no_to_ata_no(unsigned int port_no, + int is_sataii_tx4) +{ + static const unsigned char sataii_tx4_port_remap[4] = { 3, 1, 0, 2}; + return is_sataii_tx4 ? sataii_tx4_port_remap[port_no] : port_no; +} + +static unsigned int pdc_sata_nr_ports(const struct ata_port *ap) +{ + return (ap->flags & PDC_FLAG_4_PORTS) ? 4 : 2; +} + +static unsigned int pdc_sata_ata_port_to_ata_no(const struct ata_port *ap) +{ + const struct ata_host *host = ap->host; + unsigned int nr_ports = pdc_sata_nr_ports(ap); + unsigned int i; + + for(i = 0; i < nr_ports && host->ports[i] != ap; ++i) + ; + BUG_ON(i >= nr_ports); + return pdc_port_no_to_ata_no(i, pdc_is_sataii_tx4(ap->flags)); +} + +static unsigned int pdc_sata_hotplug_offset(const struct ata_port *ap) +{ + return (ap->flags & PDC_FLAG_GEN_II) ? PDC2_SATA_PLUG_CSR : PDC_SATA_PLUG_CSR; +} + static void pdc_freeze(struct ata_port *ap) { void __iomem *mmio = ap->ioaddr.cmd_addr; @@ -643,6 +634,29 @@ static void pdc_freeze(struct ata_port *ap) readl(mmio + PDC_CTLSTAT); /* flush */ } +static void pdc_sata_freeze(struct ata_port *ap) +{ + struct ata_host *host = ap->host; + void __iomem *host_mmio = host->iomap[PDC_MMIO_BAR]; + unsigned int hotplug_offset = pdc_sata_hotplug_offset(ap); + unsigned int ata_no = pdc_sata_ata_port_to_ata_no(ap); + u32 hotplug_status; + + /* Disable hotplug events on this port. + * + * Locking: + * 1) hotplug register accesses must be serialised via host->lock + * 2) ap->lock == &ap->host->lock + * 3) ->freeze() and ->thaw() are called with ap->lock held + */ + hotplug_status = readl(host_mmio + hotplug_offset); + hotplug_status |= 0x11 << (ata_no + 16); + writel(hotplug_status, host_mmio + hotplug_offset); + readl(host_mmio + hotplug_offset); /* flush */ + + pdc_freeze(ap); +} + static void pdc_thaw(struct ata_port *ap) { void __iomem *mmio = ap->ioaddr.cmd_addr; @@ -658,24 +672,32 @@ static void pdc_thaw(struct ata_port *ap) readl(mmio + PDC_CTLSTAT); /* flush */ } -static void pdc_common_error_handler(struct ata_port *ap, ata_reset_fn_t hardreset) +static void pdc_sata_thaw(struct ata_port *ap) { - if (!(ap->pflags & ATA_PFLAG_FROZEN)) - pdc_reset_port(ap); + struct ata_host *host = ap->host; + void __iomem *host_mmio = host->iomap[PDC_MMIO_BAR]; + unsigned int hotplug_offset = pdc_sata_hotplug_offset(ap); + unsigned int ata_no = pdc_sata_ata_port_to_ata_no(ap); + u32 hotplug_status; - /* perform recovery */ - ata_do_eh(ap, ata_std_prereset, ata_std_softreset, hardreset, - ata_std_postreset); -} + pdc_thaw(ap); -static void pdc_pata_error_handler(struct ata_port *ap) -{ - pdc_common_error_handler(ap, NULL); + /* Enable hotplug events on this port. + * Locking: see pdc_sata_freeze(). + */ + hotplug_status = readl(host_mmio + hotplug_offset); + hotplug_status |= 0x11 << ata_no; + hotplug_status &= ~(0x11 << (ata_no + 16)); + writel(hotplug_status, host_mmio + hotplug_offset); + readl(host_mmio + hotplug_offset); /* flush */ } -static void pdc_sata_error_handler(struct ata_port *ap) +static void pdc_error_handler(struct ata_port *ap) { - pdc_common_error_handler(ap, sata_std_hardreset); + if (!(ap->pflags & ATA_PFLAG_FROZEN)) + pdc_reset_port(ap); + + ata_std_error_handler(ap); } static void pdc_post_internal_cmd(struct ata_queued_cmd *qc) @@ -765,19 +787,6 @@ static void pdc_irq_clear(struct ata_port *ap) readl(mmio + PDC_INT_SEQMASK); } -static int pdc_is_sataii_tx4(unsigned long flags) -{ - const unsigned long mask = PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS; - return (flags & mask) == mask; -} - -static unsigned int pdc_port_no_to_ata_no(unsigned int port_no, - int is_sataii_tx4) -{ - static const unsigned char sataii_tx4_port_remap[4] = { 3, 1, 0, 2}; - return is_sataii_tx4 ? sataii_tx4_port_remap[port_no] : port_no; -} - static irqreturn_t pdc_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; @@ -799,6 +808,8 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance) mmio_base = host->iomap[PDC_MMIO_BAR]; + spin_lock(&host->lock); + /* read and clear hotplug flags for all ports */ if (host->ports[0]->flags & PDC_FLAG_GEN_II) hotplug_offset = PDC2_SATA_PLUG_CSR; @@ -814,11 +825,9 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance) if (mask == 0xffffffff && hotplug_status == 0) { VPRINTK("QUICK EXIT 2\n"); - return IRQ_NONE; + goto done_irq; } - spin_lock(&host->lock); - mask &= 0xffff; /* only 16 tags possible */ if (mask == 0 && hotplug_status == 0) { VPRINTK("QUICK EXIT 3\n"); @@ -885,7 +894,7 @@ static inline void pdc_packet_start(struct ata_queued_cmd *qc) readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ } -static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int pdc_qc_issue(struct ata_queued_cmd *qc) { switch (qc->tf.protocol) { case ATAPI_PROT_NODATA: @@ -905,20 +914,20 @@ static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc) break; } - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON(tf->protocol == ATA_PROT_DMA || tf->protocol == ATAPI_PROT_DMA); - ata_tf_load(ap, tf); + ata_sff_tf_load(ap, tf); } static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON(tf->protocol == ATA_PROT_DMA || tf->protocol == ATAPI_PROT_DMA); - ata_exec_command(ap, tf); + ata_sff_exec_command(ap, tf); } static int pdc_check_atapi_dma(struct ata_queued_cmd *qc) |