X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fata%2Flibata-core.c;h=7860d9f60ae458d310483cca4ffb9444b1a9d4ea;hb=21572ea58a1f99a59044febde90c31167d2f59ae;hp=48519887f94a021caa2e91e9287ad1db491e9c29;hpb=3ec25ebd69dc120d0590e64caaf1477aa88c8a93;p=linux-2.6 diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 48519887f9..7860d9f60a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -74,6 +74,65 @@ const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 }; const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 }; const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; +const struct ata_port_operations ata_base_port_ops = { + .irq_clear = ata_noop_irq_clear, + .prereset = ata_std_prereset, + .hardreset = sata_std_hardreset, + .postreset = ata_std_postreset, + .error_handler = ata_std_error_handler, +}; + +const struct ata_port_operations sata_port_ops = { + .inherits = &ata_base_port_ops, + + .qc_defer = ata_std_qc_defer, + .dev_select = ata_noop_dev_select, +}; + +const struct ata_port_operations sata_pmp_port_ops = { + .inherits = &sata_port_ops, + + .pmp_prereset = sata_pmp_std_prereset, + .pmp_hardreset = sata_pmp_std_hardreset, + .pmp_postreset = sata_pmp_std_postreset, + .error_handler = sata_pmp_error_handler, +}; + +const struct ata_port_operations ata_sff_port_ops = { + .inherits = &ata_base_port_ops, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .softreset = ata_std_softreset, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + .dev_select = ata_std_dev_select, + .check_status = ata_check_status, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .exec_command = ata_exec_command, + .data_xfer = ata_data_xfer, + .irq_on = ata_irq_on, + + .port_start = ata_sff_port_start, +}; + +const struct ata_port_operations ata_bmdma_port_ops = { + .inherits = &ata_sff_port_ops, + + .mode_filter = ata_pci_default_filter, + + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .irq_clear = ata_bmdma_irq_clear, +}; + static unsigned int ata_dev_init_params(struct ata_device *dev, u16 heads, u16 sectors); static unsigned int ata_dev_set_xfermode(struct ata_device *dev); @@ -325,6 +384,44 @@ static void ata_force_horkage(struct ata_device *dev) } } +/** + * atapi_cmd_type - Determine ATAPI command type from SCSI opcode + * @opcode: SCSI opcode + * + * Determine ATAPI command type from @opcode. + * + * LOCKING: + * None. + * + * RETURNS: + * ATAPI_{READ|WRITE|READ_CD|PASS_THRU|MISC} + */ +int atapi_cmd_type(u8 opcode) +{ + switch (opcode) { + case GPCMD_READ_10: + case GPCMD_READ_12: + return ATAPI_READ; + + case GPCMD_WRITE_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_10: + return ATAPI_WRITE; + + case GPCMD_READ_CD: + case GPCMD_READ_CD_MSF: + return ATAPI_READ_CD; + + case ATA_16: + case ATA_12: + if (atapi_passthru16) + return ATAPI_PASS_THRU; + /* fall thru */ + default: + return ATAPI_MISC; + } +} + /** * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure * @tf: Taskfile to convert @@ -2059,7 +2156,6 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, if (ata_msg_ctl(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __func__); - ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ retry: ata_tf_init(dev, &tf); @@ -2660,7 +2756,7 @@ int ata_bus_probe(struct ata_port *ap) specific sequence bass-ackwards so that PDIAG- is released by the slave device */ - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev_reverse(dev, &ap->link) { if (tries[dev->devno]) dev->class = classes[dev->devno]; @@ -3911,17 +4007,6 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) const unsigned long *timing = sata_ehc_deb_timing(ehc); int rc; - /* handle link resume */ - if ((ehc->i.flags & ATA_EHI_RESUME_LINK) && - (link->flags & ATA_LFLAG_HRST_TO_RESUME)) - ehc->i.action |= ATA_EH_HARDRESET; - - /* Some PMPs don't work with only SRST, force hardreset if PMP - * is supported. - */ - if (ap->flags & ATA_FLAG_PMP) - ehc->i.action |= ATA_EH_HARDRESET; - /* if we're about to do hardreset, nothing more to do */ if (ehc->i.action & ATA_EH_HARDRESET) return 0; @@ -3935,10 +4020,8 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) "link for reset (errno=%d)\n", rc); } - /* Wait for !BSY if the controller can wait for the first D2H - * Reg FIS and we don't know that no device is attached. - */ - if (!(link->flags & ATA_LFLAG_SKIP_D2H_BSY) && !ata_link_offline(link)) { + /* wait for !BSY if we don't know that no device is attached */ + if (!ata_link_offline(link)) { rc = ata_wait_ready(ap, deadline); if (rc && rc != -ENODEV) { ata_link_printk(link, KERN_WARNING, "device not ready " @@ -6017,9 +6100,9 @@ void ata_qc_issue(struct ata_queued_cmd *qc) if (ata_sg_setup(qc)) goto sg_err; - /* if device is sleeping, schedule softreset and abort the link */ + /* if device is sleeping, schedule reset and abort the link */ if (unlikely(qc->dev->flags & ATA_DFLAG_SLEEPING)) { - link->eh_info.action |= ATA_EH_SOFTRESET; + link->eh_info.action |= ATA_EH_RESET; ata_ehi_push_desc(&link->eh_info, "waking up from sleep"); ata_link_abort(link); return; @@ -6596,7 +6679,7 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg) */ void ata_host_resume(struct ata_host *host) { - ata_host_request_pm(host, PMSG_ON, ATA_EH_SOFTRESET, + ata_host_request_pm(host, PMSG_ON, ATA_EH_RESET, ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0); host->dev->power.power_state = PMSG_ON; @@ -6921,8 +7004,6 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev, if (!host->ops && (pi->port_ops != &ata_dummy_port_ops)) host->ops = pi->port_ops; - if (!host->private_data && pi->private_data) - host->private_data = pi->private_data; } return host; @@ -6946,6 +7027,56 @@ static void ata_host_stop(struct device *gendev, void *res) host->ops->host_stop(host); } +/** + * ata_finalize_port_ops - finalize ata_port_operations + * @ops: ata_port_operations to finalize + * + * An ata_port_operations can inherit from another ops and that + * ops can again inherit from another. This can go on as many + * times as necessary as long as there is no loop in the + * inheritance chain. + * + * Ops tables are finalized when the host is started. NULL or + * unspecified entries are inherited from the closet ancestor + * which has the method and the entry is populated with it. + * After finalization, the ops table directly points to all the + * methods and ->inherits is no longer necessary and cleared. + * + * Using ATA_OP_NULL, inheriting ops can force a method to NULL. + * + * LOCKING: + * None. + */ +static void ata_finalize_port_ops(struct ata_port_operations *ops) +{ + static spinlock_t lock = SPIN_LOCK_UNLOCKED; + const struct ata_port_operations *cur; + void **begin = (void **)ops; + void **end = (void **)&ops->inherits; + void **pp; + + if (!ops || !ops->inherits) + return; + + spin_lock(&lock); + + for (cur = ops->inherits; cur; cur = cur->inherits) { + void **inherit = (void **)cur; + + for (pp = begin; pp < end; pp++, inherit++) + if (!*pp) + *pp = *inherit; + } + + for (pp = begin; pp < end; pp++) + if (IS_ERR(*pp)) + *pp = NULL; + + ops->inherits = NULL; + + spin_unlock(&lock); +} + /** * ata_host_start - start and freeze ports of an ATA host * @host: ATA host to start ports for @@ -6971,9 +7102,13 @@ int ata_host_start(struct ata_host *host) if (host->flags & ATA_HOST_STARTED) return 0; + ata_finalize_port_ops(host->ops); + for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; + ata_finalize_port_ops(ap->ops); + if (!host->ops && !ata_port_is_dummy(ap)) host->ops = ap->ops; @@ -7035,7 +7170,7 @@ int ata_host_start(struct ata_host *host) */ /* KILLME - the only user left is ipr */ void ata_host_init(struct ata_host *host, struct device *dev, - unsigned long flags, const struct ata_port_operations *ops) + unsigned long flags, struct ata_port_operations *ops) { spin_lock_init(&host->lock); host->dev = dev; @@ -7131,9 +7266,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) /* kick EH for boot probing */ spin_lock_irqsave(ap->lock, flags); - ehi->probe_mask = - (1 << ata_link_max_devices(&ap->link)) - 1; - ehi->action |= ATA_EH_SOFTRESET; + ehi->probe_mask |= ATA_ALL_DEVICES; + ehi->action |= ATA_EH_RESET; ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; ap->pflags &= ~ATA_PFLAG_INITIALIZING; @@ -7725,7 +7859,7 @@ static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc) return AC_ERR_SYSTEM; } -const struct ata_port_operations ata_dummy_port_ops = { +struct ata_port_operations ata_dummy_port_ops = { .check_status = ata_dummy_check_status, .check_altstatus = ata_dummy_check_status, .dev_select = ata_noop_dev_select, @@ -7753,6 +7887,11 @@ const struct ata_port_info ata_dummy_port_info = { EXPORT_SYMBOL_GPL(sata_deb_timing_normal); EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); EXPORT_SYMBOL_GPL(sata_deb_timing_long); +EXPORT_SYMBOL_GPL(ata_base_port_ops); +EXPORT_SYMBOL_GPL(sata_port_ops); +EXPORT_SYMBOL_GPL(sata_pmp_port_ops); +EXPORT_SYMBOL_GPL(ata_sff_port_ops); +EXPORT_SYMBOL_GPL(ata_bmdma_port_ops); EXPORT_SYMBOL_GPL(ata_dummy_port_ops); EXPORT_SYMBOL_GPL(ata_dummy_port_info); EXPORT_SYMBOL_GPL(ata_std_bios_param); @@ -7774,6 +7913,7 @@ EXPORT_SYMBOL_GPL(ata_tf_read); EXPORT_SYMBOL_GPL(ata_noop_dev_select); EXPORT_SYMBOL_GPL(ata_std_dev_select); EXPORT_SYMBOL_GPL(sata_print_link_status); +EXPORT_SYMBOL_GPL(atapi_cmd_type); EXPORT_SYMBOL_GPL(ata_tf_to_fis); EXPORT_SYMBOL_GPL(ata_tf_from_fis); EXPORT_SYMBOL_GPL(ata_pack_xfermask); @@ -7799,11 +7939,11 @@ EXPORT_SYMBOL_GPL(ata_noop_qc_prep); EXPORT_SYMBOL_GPL(ata_bmdma_setup); EXPORT_SYMBOL_GPL(ata_bmdma_start); EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); +EXPORT_SYMBOL_GPL(ata_noop_irq_clear); EXPORT_SYMBOL_GPL(ata_bmdma_status); EXPORT_SYMBOL_GPL(ata_bmdma_stop); EXPORT_SYMBOL_GPL(ata_bmdma_freeze); EXPORT_SYMBOL_GPL(ata_bmdma_thaw); -EXPORT_SYMBOL_GPL(ata_bmdma_drive_eh); EXPORT_SYMBOL_GPL(ata_bmdma_error_handler); EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd); EXPORT_SYMBOL_GPL(ata_port_probe); @@ -7873,7 +8013,7 @@ EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch); EXPORT_SYMBOL_GPL(sata_pmp_std_prereset); EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset); EXPORT_SYMBOL_GPL(sata_pmp_std_postreset); -EXPORT_SYMBOL_GPL(sata_pmp_do_eh); +EXPORT_SYMBOL_GPL(sata_pmp_error_handler); EXPORT_SYMBOL_GPL(__ata_ehi_push_desc); EXPORT_SYMBOL_GPL(ata_ehi_push_desc); @@ -7892,6 +8032,7 @@ EXPORT_SYMBOL_GPL(ata_eh_thaw_port); EXPORT_SYMBOL_GPL(ata_eh_qc_complete); EXPORT_SYMBOL_GPL(ata_eh_qc_retry); EXPORT_SYMBOL_GPL(ata_do_eh); +EXPORT_SYMBOL_GPL(ata_std_error_handler); EXPORT_SYMBOL_GPL(ata_irq_on); EXPORT_SYMBOL_GPL(ata_dev_try_classify);