From 9506437921504df18c6601f7d09bb23d72d2f6ba Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 23 Jan 2006 13:09:37 +0900 Subject: [PATCH 1/6] [PATCH] libata: create pio/atapi task queueing wrappers Wrap pio/atapi task queueing in correspondingly named functions. This change doesn't change anything. It's preparation for follow-up pio-task/eh sync patch. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 93ae2dcc837c..71de697e2327 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1072,6 +1072,24 @@ static unsigned int ata_pio_modes(const struct ata_device *adev) timing API will get this right anyway */ } +static inline void +ata_queue_packet_task(struct ata_port *ap) +{ + queue_work(ata_wq, &ap->packet_task); +} + +static inline void +ata_queue_pio_task(struct ata_port *ap) +{ + queue_work(ata_wq, &ap->pio_task); +} + +static inline void +ata_queue_delayed_pio_task(struct ata_port *ap, unsigned long delay) +{ + queue_delayed_work(ata_wq, &ap->pio_task, delay); +} + void ata_qc_complete_internal(struct ata_queued_cmd *qc) { struct completion *waiting = qc->private_data; @@ -3414,7 +3432,7 @@ fsm_start: } if (timeout) - queue_delayed_work(ata_wq, &ap->pio_task, timeout); + ata_queue_delayed_pio_task(ap, timeout); else if (!qc_completed) goto fsm_start; } @@ -3737,26 +3755,26 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) ata_qc_set_polling(qc); ata_tf_to_host(ap, &qc->tf); ap->hsm_task_state = HSM_ST; - queue_work(ata_wq, &ap->pio_task); + ata_queue_pio_task(ap); break; case ATA_PROT_ATAPI: ata_qc_set_polling(qc); ata_tf_to_host(ap, &qc->tf); - queue_work(ata_wq, &ap->packet_task); + ata_queue_packet_task(ap); break; case ATA_PROT_ATAPI_NODATA: ap->flags |= ATA_FLAG_NOINTR; ata_tf_to_host(ap, &qc->tf); - queue_work(ata_wq, &ap->packet_task); + ata_queue_packet_task(ap); break; case ATA_PROT_ATAPI_DMA: ap->flags |= ATA_FLAG_NOINTR; ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ ap->ops->bmdma_setup(qc); /* set up bmdma */ - queue_work(ata_wq, &ap->packet_task); + ata_queue_packet_task(ap); break; default: @@ -4187,7 +4205,7 @@ static void atapi_packet_task(void *_data) /* PIO commands are handled by polling */ ap->hsm_task_state = HSM_ST; - queue_work(ata_wq, &ap->pio_task); + ata_queue_pio_task(ap); } return; From e0bfd149973d22a4330dd6665b54d1dcca07174a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 23 Jan 2006 16:31:53 +0900 Subject: [PATCH 2/6] [PATCH] ahci: stop engine during hard reset AHCI spec mandates engine to be stopped during hard resets. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/ahci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 5a6b23009897..2abc0aca5a8d 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -504,7 +504,9 @@ static void ahci_phy_reset(struct ata_port *ap) struct ata_device *dev = &ap->device[0]; u32 new_tmp, tmp; + ahci_stop_engine(ap); __sata_phy_reset(ap); + ahci_start_engine(ap); if (ap->flags & ATA_FLAG_PORT_DISABLED) return; From 22b49985f526796471c074c0e56bcebfd633a6ff Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 23 Jan 2006 21:38:44 +0900 Subject: [PATCH 3/6] [PATCH] ahci: add constants for SRST Add constants needed to perform SRST. This is preparation for adding softreset method. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/ahci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 2abc0aca5a8d..5caf6dec1d40 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -66,6 +66,8 @@ enum { AHCI_IRQ_ON_SG = (1 << 31), AHCI_CMD_ATAPI = (1 << 5), AHCI_CMD_WRITE = (1 << 6), + AHCI_CMD_RESET = (1 << 8), + AHCI_CMD_CLR_BUSY = (1 << 10), RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ @@ -85,6 +87,7 @@ enum { /* HOST_CAP bits */ HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ + HOST_CAP_CLO = (1 << 24), /* Command List Override support */ /* registers for each SATA port */ PORT_LST_ADDR = 0x00, /* command list DMA addr */ @@ -138,6 +141,7 @@ enum { PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ + PORT_CMD_CLO = (1 << 3), /* Command list override */ PORT_CMD_POWER_ON = (1 << 2), /* Power up device */ PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */ PORT_CMD_START = (1 << 0), /* Enable port DMA engine */ From 6f8b99589524f3e759e44721376abcdf88ed8915 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 24 Jan 2006 17:05:21 +0900 Subject: [PATCH 4/6] [PATCH] libata: export ata_busy_sleep Export ata_busy_sleep(), to be used by low level driver reset functions. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 9 +++------ include/linux/libata.h | 3 +++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 71de697e2327..4336fc889acd 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -61,9 +61,6 @@ #include "libata.h" -static unsigned int ata_busy_sleep (struct ata_port *ap, - unsigned long tmout_pat, - unsigned long tmout); static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev); static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev); static void ata_set_mode(struct ata_port *ap); @@ -1960,9 +1957,8 @@ err_out: * */ -static unsigned int ata_busy_sleep (struct ata_port *ap, - unsigned long tmout_pat, - unsigned long tmout) +unsigned int ata_busy_sleep (struct ata_port *ap, + unsigned long tmout_pat, unsigned long tmout) { unsigned long timer_start, timeout; u8 status; @@ -5167,6 +5163,7 @@ EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_port_disable); EXPORT_SYMBOL_GPL(ata_ratelimit); +EXPORT_SYMBOL_GPL(ata_busy_sleep); EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_error); diff --git a/include/linux/libata.h b/include/linux/libata.h index 576788de962a..45646f6ebbf5 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -500,6 +500,9 @@ extern int ata_scsi_device_suspend(struct scsi_device *); extern int ata_device_resume(struct ata_port *, struct ata_device *); extern int ata_device_suspend(struct ata_port *, struct ata_device *); extern int ata_ratelimit(void); +extern unsigned int ata_busy_sleep(struct ata_port *ap, + unsigned long timeout_pat, + unsigned long timeout); /* * Default driver ops implementations From b4dc7623c1bb258b66418261dab40f0e4cfc6d42 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 24 Jan 2006 17:05:22 +0900 Subject: [PATCH 5/6] [PATCH] libata: modify ata_dev_try_classify Make ata_dev_try_classify take @r_err to store tf error register value on completion and return device class instead of directly manipulating dev->class. This is preparation for new reset mechanism. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 4336fc889acd..1f78e246f5e0 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -830,6 +830,7 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf) * ata_dev_try_classify - Parse returned ATA device signature * @ap: ATA channel to examine * @device: Device to examine (starting at zero) + * @r_err: Value of error register on completion * * After an event -- SRST, E.D.D., or SATA COMRESET -- occurs, * an ATA/ATAPI-defined set of values is placed in the ATA @@ -842,11 +843,14 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf) * * LOCKING: * caller. + * + * RETURNS: + * Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE. */ -static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device) +static unsigned int +ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err) { - struct ata_device *dev = &ap->device[device]; struct ata_taskfile tf; unsigned int class; u8 err; @@ -857,8 +861,8 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device) ap->ops->tf_read(ap, &tf); err = tf.feature; - - dev->class = ATA_DEV_NONE; + if (r_err) + *r_err = err; /* see if device passed diags */ if (err == 1) @@ -866,18 +870,16 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device) else if ((device == 0) && (err == 0x81)) /* do nothing */ ; else - return err; + return ATA_DEV_NONE; - /* determine if device if ATA or ATAPI */ + /* determine if device is ATA or ATAPI */ class = ata_dev_classify(&tf); + if (class == ATA_DEV_UNKNOWN) - return err; + return ATA_DEV_NONE; if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0)) - return err; - - dev->class = class; - - return err; + return ATA_DEV_NONE; + return class; } /** @@ -2177,9 +2179,9 @@ void ata_bus_reset(struct ata_port *ap) /* * determine by signature whether we have ATA or ATAPI devices */ - err = ata_dev_try_classify(ap, 0); + ap->device[0].class = ata_dev_try_classify(ap, 0, &err); if ((slave_possible) && (err != 0x81)) - ata_dev_try_classify(ap, 1); + ap->device[1].class = ata_dev_try_classify(ap, 1, &err); /* re-enable interrupts */ if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */ From c19ba8af4f104cca28d548cac55c128b28dd31fb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 24 Jan 2006 17:05:22 +0900 Subject: [PATCH 6/6] [PATCH] libata: new ->probe_reset operation Add new ->probe_reset operation to ata_port_operations obsoleting ->phy_reset. The main difference from ->phy_reset is that the new operation is not allowed to manipulate libata internals directly. It's not allowed to configure or disable the port or devices. It can only succeed or fail and classify attached devices into passed @classes. This change gives more control to higher level and eases sharing reset methods with EH. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 19 ++++++++++++++++++- include/linux/libata.h | 8 +++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 1f78e246f5e0..147e1461062d 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1485,7 +1485,24 @@ static int ata_bus_probe(struct ata_port *ap) { unsigned int i, found = 0; - ap->ops->phy_reset(ap); + if (ap->ops->probe_reset) { + unsigned int classes[ATA_MAX_DEVICES]; + int rc; + + ata_port_probe(ap); + + rc = ap->ops->probe_reset(ap, classes); + if (rc == 0) { + for (i = 0; i < ATA_MAX_DEVICES; i++) + ap->device[i].class = classes[i]; + } else { + printk(KERN_ERR "ata%u: probe reset failed, " + "disabling port\n", ap->id); + ata_port_disable(ap); + } + } else + ap->ops->phy_reset(ap); + if (ap->flags & ATA_FLAG_PORT_DISABLED) goto err_out; diff --git a/include/linux/libata.h b/include/linux/libata.h index 45646f6ebbf5..a84d1c3a5429 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -148,9 +148,9 @@ enum { ATA_FLAG_PORT_DISABLED = (1 << 2), /* port is disabled, ignore it */ ATA_FLAG_SATA = (1 << 3), ATA_FLAG_NO_LEGACY = (1 << 4), /* no legacy mode check */ - ATA_FLAG_SRST = (1 << 5), /* use ATA SRST, not E.D.D. */ + ATA_FLAG_SRST = (1 << 5), /* (obsolete) use ATA SRST, not E.D.D. */ ATA_FLAG_MMIO = (1 << 6), /* use MMIO, not PIO */ - ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */ + ATA_FLAG_SATA_RESET = (1 << 7), /* (obsolete) use COMRESET */ ATA_FLAG_PIO_DMA = (1 << 8), /* PIO cmds via DMA */ ATA_FLAG_NOINTR = (1 << 9), /* FIXME: Remove this once * proper HSM is in place. */ @@ -419,7 +419,9 @@ struct ata_port_operations { u8 (*check_altstatus)(struct ata_port *ap); void (*dev_select)(struct ata_port *ap, unsigned int device); - void (*phy_reset) (struct ata_port *ap); + void (*phy_reset) (struct ata_port *ap); /* obsolete */ + int (*probe_reset) (struct ata_port *ap, unsigned int *classes); + void (*post_set_mode) (struct ata_port *ap); int (*check_atapi_dma) (struct ata_queued_cmd *qc);