linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/6] libata: export ata_hsm_move()
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
  2006-05-11 15:11 ` [PATCH 01/14] libata-hp-prep: add flags and eh_info/context fields for hotplug Tejun Heo
@ 2006-05-11 15:11 ` Tejun Heo
  2006-05-11 15:11 ` [PATCH 02/14] libata-hp-prep: implement ata_dev_init() Tejun Heo
                   ` (18 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

ata_hsm_move() will be used by LLDDs which depend on standard PIO HSM
but implement their own interrupt handlers.

---

 drivers/scsi/libata-core.c |    6 +++---
 include/linux/libata.h     |    2 ++
 2 files changed, 5 insertions(+), 3 deletions(-)

80a810231596efc4c208307250cfea7c2b55cb15
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 7259646..9acfdc7 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -4099,9 +4099,8 @@ static void ata_hsm_qc_complete(struct a
  *	RETURNS:
  *	1 when poll next status needed, 0 otherwise.
  */
-
-static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
-			 u8 status, int in_wq)
+int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
+		 u8 status, int in_wq)
 {
 	unsigned long flags = 0;
 	int poll_next;
@@ -5821,6 +5820,7 @@ EXPORT_SYMBOL_GPL(ata_device_add);
 EXPORT_SYMBOL_GPL(ata_host_set_remove);
 EXPORT_SYMBOL_GPL(ata_sg_init);
 EXPORT_SYMBOL_GPL(ata_sg_init_one);
+EXPORT_SYMBOL_GPL(ata_hsm_move);
 EXPORT_SYMBOL_GPL(ata_qc_complete);
 EXPORT_SYMBOL_GPL(ata_qc_complete_multiple);
 EXPORT_SYMBOL_GPL(ata_qc_issue_prot);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 9e06d82..815087f 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -704,6 +704,8 @@ extern void ata_bmdma_drive_eh(struct at
 			       ata_postreset_fn_t postreset);
 extern void ata_bmdma_error_handler(struct ata_port *ap);
 extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc);
+extern int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
+			u8 status, int in_wq);
 extern void ata_qc_complete(struct ata_queued_cmd *qc);
 extern int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active,
 				    void (*finish_qc)(struct ata_queued_cmd *));
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 01/14] libata-hp-prep: add flags and eh_info/context fields for hotplug
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
@ 2006-05-11 15:11 ` Tejun Heo
  2006-05-11 15:11 ` [PATCH 1/6] libata: export ata_hsm_move() Tejun Heo
                   ` (19 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Add hotplug related flags and eh_info/context fields.

---

 include/linux/libata.h |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)

d60dd05d2cfd4a63b7ce869694c3060d2aeab9d8
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 97e25a6..1f6e48e 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -130,6 +130,9 @@ enum {
 
 	ATA_DFLAG_PIO		= (1 << 8), /* device currently in PIO mode */
 
+	ATA_DFLAG_DETACH	= (1 << 16),
+	ATA_DFLAG_DETACHED	= (1 << 17),
+
 	ATA_DEV_UNKNOWN		= 0,	/* unknown device */
 	ATA_DEV_ATA		= 1,	/* ATA device */
 	ATA_DEV_ATA_UNSUP	= 2,	/* ATA device (unsupported) */
@@ -161,6 +164,9 @@ enum {
 	ATA_FLAG_EH_PENDING	= (1 << 16), /* EH pending */
 	ATA_FLAG_FROZEN		= (1 << 17), /* port is frozen */
 	ATA_FLAG_RECOVERED	= (1 << 18), /* recovery action performed */
+	ATA_FLAG_LOADING	= (1 << 19), /* boot/loading probe */
+	ATA_FLAG_UNLOADING	= (1 << 20), /* module is unloading */
+	ATA_FLAG_SCSI_HOTPLUG	= (1 << 21), /* SCSI hotplug scheduled */
 
 	ATA_FLAG_DISABLED	= (1 << 22), /* port is disabled, ignore it */
 	ATA_FLAG_SUSPENDED	= (1 << 23), /* port is suspended (power) */
@@ -435,6 +441,7 @@ struct ata_eh_info {
 	u32			serror;		/* SError from LLDD */
 	unsigned int		err_mask;	/* port-wide err_mask */
 	unsigned int		action;		/* ATA_EH_* action mask */
+	unsigned int		probe_mask;
 	char			desc[ATA_EH_DESC_LEN];
 	int			desc_len;
 };
@@ -442,7 +449,9 @@ struct ata_eh_info {
 struct ata_eh_context {
 	struct ata_eh_info	i;
 	int			tries[ATA_MAX_DEVICES];
+	unsigned int		classes[ATA_MAX_DEVICES];
 	unsigned int		flags;		/* ATA_EHC_* */
+	unsigned int		did_probe_mask;
 };
 
 struct ata_port {
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHSET 07/11] prep LLDDs for hotplug support, take 1
@ 2006-05-11 15:11 Tejun Heo
  2006-05-11 15:11 ` [PATCH 01/14] libata-hp-prep: add flags and eh_info/context fields for hotplug Tejun Heo
                   ` (20 more replies)
  0 siblings, 21 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide,
	htejun

Hairu.

This is part of patchset series described in [T].

This is the first take of prep-LLDDs-for-hotplug-support patchset.
Some of patches in this patchset are from the first take of
add-hotplug-support patchset.

Things worth noting are

* Simply exporting ata_hsm_move() and calling the function with
  appropriate status is good enough for driving HSM for LLDDs
  implementing their own irq handlers.  sata_sil's new irq handler
  now uses it.

* TF faking is removed from sata_sil24.

This patchset is against

  upstream (acc696d93dcf993dec123d69d599979e1456ffec)
  + [1] prep-for-new-EH patchset
  + [2] new-EH-framework patchset, take 3
  + [3] new-EH-implementation patchset, take 3
  + [4] merge-irq-pio patchset
  + [5] add-NCQ-support patchset, take 3
  + [6] prep for hotplug support, take 2

--
tejun

[T] http://article.gmane.org/gmane.linux.ide/9957
[1] http://article.gmane.org/gmane.linux.ide/9959
[2] http://article.gmane.org/gmane.linux.ide/9984
[3] http://article.gmane.org/gmane.linux.ide/9995
[4] http://article.gmane.org/gmane.linux.ide/10005
[5] http://article.gmane.org/gmane.linux.ide/10011
[6] http://article.gmane.org/gmane.linux.ide/10028



^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 02/14] libata-hp-prep: implement ata_dev_init()
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
  2006-05-11 15:11 ` [PATCH 01/14] libata-hp-prep: add flags and eh_info/context fields for hotplug Tejun Heo
  2006-05-11 15:11 ` [PATCH 1/6] libata: export ata_hsm_move() Tejun Heo
@ 2006-05-11 15:11 ` Tejun Heo
  2006-05-11 15:11 ` [PATCH 2/6] sata_sil: add new constants in preparation for new interrupt handler Tejun Heo
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Move initialization of struct ata_device into ata_dev_init() in
preparation for hotplug.  This patch calls ata_dev_init() from
ata_host_init() and thus makes no functional difference.

---

 drivers/scsi/libata-core.c |   28 ++++++++++++++++++++++------
 1 files changed, 22 insertions(+), 6 deletions(-)

bf81344569d3ceb459fa55121a0d69d9ed52f10e
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 54240db..d307164 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -5108,6 +5108,27 @@ static void ata_host_remove(struct ata_p
 }
 
 /**
+ *	ata_dev_init - Initialize an ata_device structure
+ *	@dev: Device structure to initialize
+ *
+ *	Initialize @dev in preparation for probing.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+void ata_dev_init(struct ata_device *dev)
+{
+	struct ata_port *ap = dev->ap;
+
+	memset((void *)dev, 0, sizeof(*dev));
+	dev->devno = dev - ap->device;
+	dev->pio_mask = UINT_MAX;
+	dev->mwdma_mask = UINT_MAX;
+	dev->udma_mask = UINT_MAX;
+	ata_ering_init(&dev->ering, ATA_DEV_ERING_SIZE);
+}
+
+/**
  *	ata_host_init - Initialize an ata_port structure
  *	@ap: Structure to initialize
  *	@host: associated SCSI mid-layer structure
@@ -5121,7 +5142,6 @@ static void ata_host_remove(struct ata_p
  *	LOCKING:
  *	Inherited from caller.
  */
-
 static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
 			  struct ata_host_set *host_set,
 			  const struct ata_probe_ent *ent, unsigned int port_no)
@@ -5163,11 +5183,7 @@ static void ata_host_init(struct ata_por
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
 		struct ata_device *dev = &ap->device[i];
 		dev->ap = ap;
-		dev->devno = i;
-		dev->pio_mask = UINT_MAX;
-		dev->mwdma_mask = UINT_MAX;
-		dev->udma_mask = UINT_MAX;
-		ata_ering_init(&dev->ering, ATA_DEV_ERING_SIZE);
+		ata_dev_init(dev);
 	}
 
 #ifdef ATA_IRQ_TRAP
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 2/6] sata_sil: add new constants in preparation for new interrupt handler
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (2 preceding siblings ...)
  2006-05-11 15:11 ` [PATCH 02/14] libata-hp-prep: implement ata_dev_init() Tejun Heo
@ 2006-05-11 15:11 ` Tejun Heo
  2006-05-11 15:11 ` [PATCH 10/14] libata-hp-prep: implement sata_phy_debounce() Tejun Heo
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

sata_sil is about to get a brand new interrupt handler.  Add relevant
constants.

---

 drivers/scsi/sata_sil.c |   24 ++++++++++++++++++++----
 1 files changed, 20 insertions(+), 4 deletions(-)

3d5ca9ae81dfd7cc0220feb7da6b148dad866c0e
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 3e998b7..1c0a751 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -54,6 +54,7 @@ enum {
 	 */
 	SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
 	SIL_FLAG_MOD15WRITE	= (1 << 30),
+
 	SIL_DFL_HOST_FLAGS	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_MMIO,
 
@@ -84,6 +85,20 @@ enum {
 	/* BMDMA/BMDMA2 */
 	SIL_INTR_STEERING	= (1 << 1),
 
+	SIL_DMA_ENABLE		= (1 << 0),  /* DMA run switch */
+	SIL_DMA_RDWR		= (1 << 3),  /* DMA Rd-Wr */
+	SIL_DMA_SATA_IRQ	= (1 << 4),  /* OR of all SATA IRQs */
+	SIL_DMA_ACTIVE		= (1 << 16), /* DMA running */
+	SIL_DMA_ERROR		= (1 << 17), /* PCI bus error */
+	SIL_DMA_COMPLETE	= (1 << 18), /* cmd complete / IRQ pending */
+	SIL_DMA_N_SATA_IRQ	= (1 << 6),  /* SATA_IRQ for the next channel */
+	SIL_DMA_N_ACTIVE	= (1 << 24), /* ACTIVE for the next channel */
+	SIL_DMA_N_ERROR		= (1 << 25), /* ERROR for the next channel */
+	SIL_DMA_N_COMPLETE	= (1 << 26), /* COMPLETE for the next channel */
+
+	/* SIEN */
+	SIL_SIEN_N		= (1 << 16), /* triggered by SError.N */
+
 	/*
 	 * Others
 	 */
@@ -225,6 +240,7 @@ static const struct {
 	unsigned long tf;	/* ATA taskfile register block */
 	unsigned long ctl;	/* ATA control/altstatus register block */
 	unsigned long bmdma;	/* DMA register block */
+	unsigned long bmdma2;	/* DMA register block #2 */
 	unsigned long fifo_cfg;	/* FIFO Valid Byte Count and Control */
 	unsigned long scr;	/* SATA control register block */
 	unsigned long sien;	/* SATA Interrupt Enable register */
@@ -232,10 +248,10 @@ static const struct {
 	unsigned long sfis_cfg;	/* SATA FIS reception config register */
 } sil_port[] = {
 	/* port 0 ... */
-	{ 0x80, 0x8A, 0x00, 0x40, 0x100, 0x148, 0xb4, 0x14c },
-	{ 0xC0, 0xCA, 0x08, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc },
-	{ 0x280, 0x28A, 0x200, 0x240, 0x300, 0x348, 0x2b4, 0x34c },
-	{ 0x2C0, 0x2CA, 0x208, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },
+	{ 0x80, 0x8A, 0x00, 0x10, 0x40, 0x100, 0x148, 0xb4, 0x14c },
+	{ 0xC0, 0xCA, 0x08, 0x18, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc },
+	{ 0x280, 0x28A, 0x200, 0x210, 0x240, 0x300, 0x348, 0x2b4, 0x34c },
+	{ 0x2C0, 0x2CA, 0x208, 0x218, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },
 	/* ... port 3 */
 };
 
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 3/6] sata_sil: new interrupt handler
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (14 preceding siblings ...)
  2006-05-11 15:11 ` [PATCH 09/14] libata-hp-prep: make probing related functions global Tejun Heo
@ 2006-05-11 15:11 ` Tejun Heo
  2006-05-11 15:12 ` [PATCH 13/14] libata-hp-prep: add prereset() method and implement ata_std_prereset() Tejun Heo
                   ` (4 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

The DMA complete bit of these controllers reflects ATA IRQ status
while no DMA command is in progress.  So, we can tell whether the
controller is raising an interrupt or not in deterministic manner.
This patch gives sata_sil its own interrupt handler which behaves much
better than the original one in terms of error detection and handling.
This change is also necessary for later hotplug support.

Further improvements are possible, in both 2 and 4 ports versions, we
can get all status with only one readl and using custom bmdma
operations can further cut down register accesses.

---

 drivers/scsi/sata_sil.c |   94 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 93 insertions(+), 1 deletions(-)

4cd6609bcdca30ea40436a695497ab35217ad4b5
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 1c0a751..94fdbf0 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -111,6 +111,8 @@ static void sil_dev_config(struct ata_po
 static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static void sil_post_set_mode (struct ata_port *ap);
+static irqreturn_t sil_interrupt(int irq, void *dev_instance,
+				 struct pt_regs *regs);
 static void sil_freeze(struct ata_port *ap);
 static void sil_thaw(struct ata_port *ap);
 
@@ -195,7 +197,7 @@ static const struct ata_port_operations 
 	.thaw			= sil_thaw,
 	.error_handler		= ata_bmdma_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
-	.irq_handler		= ata_interrupt,
+	.irq_handler		= sil_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.scr_read		= sil_scr_read,
 	.scr_write		= sil_scr_write,
@@ -335,6 +337,96 @@ static void sil_scr_write (struct ata_po
 		writel(val, mmio);
 }
 
+static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
+{
+	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+	u8 status;
+
+	if (unlikely(!qc || qc->tf.ctl & ATA_NIEN))
+		goto freeze;
+
+	/* Check whether we are expecting interrupt in this state */
+	switch (ap->hsm_task_state) {
+	case HSM_ST_FIRST:
+		/* Some pre-ATAPI-4 devices assert INTRQ
+		 * at this state when ready to receive CDB.
+		 */
+
+		/* Check the ATA_DFLAG_CDB_INTR flag is enough here.
+		 * The flag was turned on only for atapi devices.
+		 * No need to check is_atapi_taskfile(&qc->tf) again.
+		 */
+		if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+			goto err_hsm;
+		break;
+	case HSM_ST_LAST:
+		if (qc->tf.protocol == ATA_PROT_DMA ||
+		    qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+			/* clear DMA-Start bit */
+			ap->ops->bmdma_stop(qc);
+
+			if (bmdma2 & SIL_DMA_ERROR) {
+				qc->err_mask |= AC_ERR_HOST_BUS;
+				ap->hsm_task_state = HSM_ST_ERR;
+			}
+		}
+		break;
+	case HSM_ST:
+		break;
+	default:
+		goto err_hsm;
+	}
+
+	/* check main status, clearing INTRQ */
+	status = ata_chk_status(ap);
+	if (unlikely(status & ATA_BUSY))
+		goto err_hsm;
+
+	/* ack bmdma irq events */
+	ap->ops->irq_clear(ap);
+
+	/* kick HSM in the ass */
+	ata_hsm_move(ap, qc, status, 0);
+
+	return;
+
+ err_hsm:
+	qc->err_mask |= AC_ERR_HSM;
+ freeze:
+	ata_port_freeze(ap);
+}
+
+static irqreturn_t sil_interrupt(int irq, void *dev_instance,
+				 struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	void __iomem *mmio_base = host_set->mmio_base;
+	int handled = 0;
+	unsigned long flags;
+	int i;
+
+	/* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
+	spin_lock_irqsave(&host_set->lock, flags);
+
+	for (i = 0; i < host_set->n_ports; i++) {
+		struct ata_port *ap = host_set->ports[i];
+		u32 bmdma2 = readl(mmio_base + sil_port[ap->port_no].bmdma2);
+
+		if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
+			continue;
+
+		if (!(bmdma2 & SIL_DMA_COMPLETE))
+			continue;
+
+		sil_host_intr(ap, bmdma2);
+		handled = 1;
+	}
+
+	spin_unlock_irqrestore(&host_set->lock, flags);
+
+	return IRQ_RETVAL(handled);
+}
+
 static void sil_freeze(struct ata_port *ap)
 {
 	void __iomem *mmio_base = ap->host_set->mmio_base;
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 5/6] sata_sil24: use sata_phy_debounce() in sil24_hardreset()
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (5 preceding siblings ...)
  2006-05-11 15:11 ` [PATCH 05/14] libata-hp-prep: use __ata_scsi_find_dev() Tejun Heo
@ 2006-05-11 15:11 ` Tejun Heo
  2006-05-11 15:11 ` [PATCH 08/14] libata-hp-prep: add ata_hotplug_wq Tejun Heo
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Do phy debouncing instead of unconditional wait after DEV_RST.

---

 drivers/scsi/sata_sil24.c |   13 +++++++++----
 1 files changed, 9 insertions(+), 4 deletions(-)

b8c4776dbd446dd2087689d23c1a6ca153abd293
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index 629679e..72219fa 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -591,7 +591,7 @@ static int sil24_hardreset(struct ata_po
 {
 	void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
 	const char *reason;
-	int tout_msec;
+	int tout_msec, rc;
 	u32 tmp;
 
 	/* sil24 does the right thing(tm) without any protection */
@@ -605,10 +605,15 @@ static int sil24_hardreset(struct ata_po
 	tmp = ata_wait_register(port + PORT_CTRL_STAT,
 				PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10, tout_msec);
 
-	/* SStatus oscillates between zero and valid status for short
-	 * duration after DEV_RST, give it time to settle.
+	/* SStatus oscillates between zero and valid status after
+	 * DEV_RST, debounce it.
 	 */
-	msleep(100);
+	rc = sata_phy_debounce(ap, ATA_DEBOUNCE_INTERVAL,
+			       ATA_DEBOUNCE_DURATION, ATA_DEBOUNCE_TIMEOUT);
+	if (rc) {
+		reason = "PHY debouncing failed";
+		goto err;
+	}
 
 	if (tmp & PORT_CS_DEV_RST) {
 		if (ata_port_offline(ap))
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 09/14] libata-hp-prep: make probing related functions global
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (13 preceding siblings ...)
  2006-05-11 15:11 ` [PATCH 4/6] sata_sil24: rename PORT_PRB to PORT_LRAM and add PORT_LRAM_SLOT_SZ Tejun Heo
@ 2006-05-11 15:11 ` Tejun Heo
  2006-05-11 15:11 ` [PATCH 3/6] sata_sil: new interrupt handler Tejun Heo
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Hotplug will be implemented in libata-eh.c.  Make ata_dev_read_id()
and ata_dev_configure() global.

---

 drivers/scsi/libata-core.c |    6 +++---
 drivers/scsi/libata.h      |    3 +++
 2 files changed, 6 insertions(+), 3 deletions(-)

8d89cdee6d673f4e1915b3ec587dafec44456942
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 1f587aa..1861373 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1164,8 +1164,8 @@ unsigned int ata_pio_need_iordy(const st
  *	RETURNS:
  *	0 on success, -errno otherwise.
  */
-static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
-			   int post_reset, u16 *id)
+int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
+		    int post_reset, u16 *id)
 {
 	struct ata_port *ap = dev->ap;
 	unsigned int class = *p_class;
@@ -1289,7 +1289,7 @@ static void ata_dev_config_ncq(struct at
  *	RETURNS:
  *	0 on success, -errno otherwise
  */
-static int ata_dev_configure(struct ata_device *dev, int print_info)
+int ata_dev_configure(struct ata_device *dev, int print_info)
 {
 	struct ata_port *ap = dev->ap;
 	const u16 *id = dev->id;
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index ff50442..24dd534 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -50,6 +50,9 @@ extern void ata_port_flush_task(struct a
 extern unsigned ata_exec_internal(struct ata_device *dev,
 				  struct ata_taskfile *tf, const u8 *cdb,
 				  int dma_dir, void *buf, unsigned int buflen);
+extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
+			   int post_reset, u16 *id);
+extern int ata_dev_configure(struct ata_device *dev, int print_info);
 extern int ata_down_sata_spd_limit(struct ata_port *ap);
 extern int ata_set_sata_spd_needed(struct ata_port *ap);
 extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0);
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 03/14] libata-hp-prep: make some ata_device fields persistent
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (11 preceding siblings ...)
  2006-05-11 15:11 ` [PATCH 06/14] libata-hp-prep: implement ap->hw_sata_spd_limit Tejun Heo
@ 2006-05-11 15:11 ` Tejun Heo
  2006-05-11 15:11 ` [PATCH 4/6] sata_sil24: rename PORT_PRB to PORT_LRAM and add PORT_LRAM_SLOT_SZ Tejun Heo
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Lifetimes of some fields span over device plugging/unplugging.  This
patch moves such persistent fields to the top of ata_device and
separate them with ATA_DEVICE_CLEAR_OFFSET.  Fields above the offset
are initialized once during host initializatino while all other fields
are cleared before hotplugging.  Currently ->ap, devno and part of
flags are persistent.

Note that flags is partially cleared while holding host_set lock.
This is to synchronize with later warm plug implementation which will
record hotplug request in dev->flags.

---

 drivers/scsi/libata-core.c |   14 ++++++++++++--
 include/linux/libata.h     |    8 ++++++--
 2 files changed, 18 insertions(+), 4 deletions(-)

480d38b7f94a98fe9c9b33db932d94652cfed779
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index d307164..6accef3 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -5119,9 +5119,18 @@ static void ata_host_remove(struct ata_p
 void ata_dev_init(struct ata_device *dev)
 {
 	struct ata_port *ap = dev->ap;
+	unsigned long flags;
+
+	/* High bits of dev->flags are used to record warm plug
+	 * requests which occur asynchronously.  Synchronize using
+	 * host_set lock.
+	 */
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	dev->flags &= ~ATA_DFLAG_INIT_MASK;
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
 
-	memset((void *)dev, 0, sizeof(*dev));
-	dev->devno = dev - ap->device;
+	memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0,
+	       sizeof(*dev) - ATA_DEVICE_CLEAR_OFFSET);
 	dev->pio_mask = UINT_MAX;
 	dev->mwdma_mask = UINT_MAX;
 	dev->udma_mask = UINT_MAX;
@@ -5183,6 +5192,7 @@ static void ata_host_init(struct ata_por
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
 		struct ata_device *dev = &ap->device[i];
 		dev->ap = ap;
+		dev->devno = i;
 		ata_dev_init(dev);
 	}
 
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 1f6e48e..99a78cf 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -129,6 +129,7 @@ enum {
 	ATA_DFLAG_CFG_MASK	= (1 << 8) - 1,
 
 	ATA_DFLAG_PIO		= (1 << 8), /* device currently in PIO mode */
+	ATA_DFLAG_INIT_MASK	= (1 << 16) - 1,
 
 	ATA_DFLAG_DETACH	= (1 << 16),
 	ATA_DFLAG_DETACHED	= (1 << 17),
@@ -408,10 +409,11 @@ struct ata_ering {
 
 struct ata_device {
 	struct ata_port		*ap;
-	u64			n_sectors;	/* size of device, if ATA */
+	unsigned int		devno;		/* 0 or 1 */
 	unsigned long		flags;		/* ATA_DFLAG_xxx */
+	/* fields above n_sectors are not cleared across device init */
+	u64			n_sectors;	/* size of device, if ATA */
 	unsigned int		class;		/* ATA_DEV_xxx */
-	unsigned int		devno;		/* 0 or 1 */
 	u16			id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
 	u8			pio_mode;
 	u8			dma_mode;
@@ -436,6 +438,8 @@ struct ata_device {
 	DEFINE_ATA_ERING	(ering, ATA_DEV_ERING_SIZE);
 };
 
+#define ATA_DEVICE_CLEAR_OFFSET		offsetof(struct ata_device, n_sectors)
+
 struct ata_eh_info {
 	struct ata_device	*dev;		/* offending device */
 	u32			serror;		/* SError from LLDD */
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 4/6] sata_sil24: rename PORT_PRB to PORT_LRAM and add PORT_LRAM_SLOT_SZ
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (12 preceding siblings ...)
  2006-05-11 15:11 ` [PATCH 03/14] libata-hp-prep: make some ata_device fields persistent Tejun Heo
@ 2006-05-11 15:11 ` Tejun Heo
  2006-05-11 15:11 ` [PATCH 09/14] libata-hp-prep: make probing related functions global Tejun Heo
                   ` (6 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

PORT_PRB is a misnomer as the area also contains other stuff.  Rename
it to PORT_LRAM and add PORT_LRAM_SLOT_SZ.

---

 drivers/scsi/sata_sil24.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

7b6eafd6c25c22b66aa7dd610099569596606a1c
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index 4747047..629679e 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -98,7 +98,9 @@ enum {
 	 * (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2)
 	 */
 	PORT_REGS_SIZE		= 0x2000,
-	PORT_PRB		= 0x0000, /* (32 bytes PRB + 16 bytes SGEs * 6) * 31 (3968 bytes) */
+
+	PORT_LRAM		= 0x0000, /* 31 LRAM slots and PM regs */
+	PORT_LRAM_SLOT_SZ	= 0x0080, /* 32 bytes PRB + 2 SGE, ACT... */
 
 	PORT_PM			= 0x0f80, /* 8 bytes PM * 16 (128 bytes) */
 		/* 32 bit regs */
@@ -1103,7 +1105,7 @@ static int sil24_init_one(struct pci_dev
 		void __iomem *port = port_base + i * PORT_REGS_SIZE;
 		unsigned long portu = (unsigned long)port;
 
-		probe_ent->port[i].cmd_addr = portu + PORT_PRB;
+		probe_ent->port[i].cmd_addr = portu;
 		probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
 
 		ata_std_ports(&probe_ent->port[i]);
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 08/14] libata-hp-prep: add ata_hotplug_wq
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (6 preceding siblings ...)
  2006-05-11 15:11 ` [PATCH 5/6] sata_sil24: use sata_phy_debounce() in sil24_hardreset() Tejun Heo
@ 2006-05-11 15:11 ` Tejun Heo
  2006-05-11 15:11 ` [PATCH 04/14] libata-hp-prep: update ata_scsi_find_dev() and friends Tejun Heo
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

It's best to run ATA hotplug from EH but attaching SCSI devices needs
working EH.  ata_hotplug_wq is used to give SCSI hotplug operations a
separate context.

---

 drivers/scsi/libata-core.c |    9 +++++++++
 drivers/scsi/libata.h      |    1 +
 2 files changed, 10 insertions(+), 0 deletions(-)

60b0f9061e9ce6345e549a38d73f4759daae0339
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 6da1005..1f587aa 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -69,6 +69,8 @@ static void ata_dev_xfermask(struct ata_
 static unsigned int ata_unique_id = 1;
 static struct workqueue_struct *ata_wq;
 
+struct workqueue_struct *ata_hotplug_wq;
+
 int atapi_enabled = 1;
 module_param(atapi_enabled, int, 0444);
 MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)");
@@ -5588,6 +5590,12 @@ static int __init ata_init(void)
 	if (!ata_wq)
 		return -ENOMEM;
 
+	ata_hotplug_wq = create_singlethread_workqueue("ata_hotplug");
+	if (!ata_hotplug_wq) {
+		destroy_workqueue(ata_wq);
+		return -ENOMEM;
+	}
+
 	printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
 	return 0;
 }
@@ -5595,6 +5603,7 @@ static int __init ata_init(void)
 static void __exit ata_exit(void)
 {
 	destroy_workqueue(ata_wq);
+	destroy_workqueue(ata_hotplug_wq);
 }
 
 module_init(ata_init);
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index 134cb4d..ff50442 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -39,6 +39,7 @@ struct ata_scsi_args {
 };
 
 /* libata-core.c */
+extern struct workqueue_struct *ata_hotplug_wq;
 extern int atapi_enabled;
 extern int atapi_dmadir;
 extern int libata_fua;
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 04/14] libata-hp-prep: update ata_scsi_find_dev() and friends
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (7 preceding siblings ...)
  2006-05-11 15:11 ` [PATCH 08/14] libata-hp-prep: add ata_hotplug_wq Tejun Heo
@ 2006-05-11 15:11 ` Tejun Heo
  2006-05-11 15:11 ` [PATCH 6/6] sata_sil24: kill ops->tf_read() and use ata_std_noop_check_status() Tejun Heo
                   ` (11 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Separate out ata_find_dev() and __ata_scsi_find_dev() from
ata_scsi_find_dev().  ata_find_dev() checks ATA_FLAG_SLAVE_POSS for
id==1 case, so all three functions return NULL if id==1 is specified
for !SLAVE_POSS port.  These will be used by later hotplug
implementation.

---

 drivers/scsi/libata-scsi.c |   40 +++++++++++++++++++++++++---------------
 1 files changed, 25 insertions(+), 15 deletions(-)

9ac5a3ff896cfe11b51d5e781f2b4e2137b10142
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 996058a..bb40309 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -52,8 +52,12 @@
 #define SECTOR_SIZE	512
 
 typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scsicmd);
-static struct ata_device *
-ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev);
+
+static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
+					const struct scsi_device *scsidev);
+static struct ata_device * ata_scsi_find_dev(struct ata_port *ap,
+					    const struct scsi_device *scsidev);
+
 
 #define RW_RECOVERY_MPAGE 0x1
 #define RW_RECOVERY_MPAGE_LEN 12
@@ -2308,6 +2312,23 @@ static unsigned int atapi_xlat(struct at
 	return 0;
 }
 
+static struct ata_device * ata_find_dev(struct ata_port *ap, int id)
+{
+	if (likely(id == 0 || (id == 1 && ap->flags & ATA_FLAG_SLAVE_POSS)))
+		return &ap->device[id];
+	return NULL;
+}
+
+static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
+					const struct scsi_device *scsidev)
+{
+	/* skip commands not addressed to targets we simulate */
+	if (unlikely(scsidev->channel || scsidev->lun))
+		return NULL;
+
+	return ata_find_dev(ap, scsidev->id);
+}
+
 /**
  *	ata_scsi_find_dev - lookup ata_device from scsi_cmnd
  *	@ap: ATA port to which the device is attached
@@ -2324,23 +2345,12 @@ static unsigned int atapi_xlat(struct at
  *	RETURNS:
  *	Associated ATA device, or %NULL if not found.
  */
-
 static struct ata_device *
 ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev)
 {
-	struct ata_device *dev;
-
-	/* skip commands not addressed to targets we simulate */
-	if (likely(scsidev->id < ATA_MAX_DEVICES))
-		dev = &ap->device[scsidev->id];
-	else
-		return NULL;
-
-	if (unlikely((scsidev->channel != 0) ||
-		     (scsidev->lun != 0)))
-		return NULL;
+	struct ata_device *dev = __ata_scsi_find_dev(ap, scsidev);
 
-	if (unlikely(!ata_dev_enabled(dev)))
+	if (unlikely(!dev || !ata_dev_enabled(dev)))
 		return NULL;
 
 	if (!atapi_enabled || (ap->flags & ATA_FLAG_NO_ATAPI)) {
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 06/14] libata-hp-prep: implement ap->hw_sata_spd_limit
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (10 preceding siblings ...)
  2006-05-11 15:11 ` [PATCH 07/14] libata-hp-prep: store attached SCSI device Tejun Heo
@ 2006-05-11 15:11 ` Tejun Heo
  2006-05-11 15:11 ` [PATCH 03/14] libata-hp-prep: make some ata_device fields persistent Tejun Heo
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Add ap->hw_sata_spd_limit and initialize it once during the boot
initialization (or driver load initialization).  ap->sata_spd_limit is
reset to ap->hw_sata_spd_limit on hotplug.  This prevents limits
introduced by earlier devices from affecting new devices.

---

 drivers/scsi/libata-core.c |   21 ++++++++++++---------
 include/linux/libata.h     |    1 +
 2 files changed, 13 insertions(+), 9 deletions(-)

658f9435c1ea00f1222bc0090b4bffe41111604f
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 6accef3..6da1005 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2456,17 +2456,9 @@ static int sata_phy_resume(struct ata_po
  */
 void ata_std_probeinit(struct ata_port *ap)
 {
-	u32 scontrol;
-
 	/* resume link */
 	sata_phy_resume(ap);
 
-	/* init sata_spd_limit to the current value */
-	if (ata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
-		int spd = (scontrol >> 4) & 0xf;
-		ap->sata_spd_limit &= (1 << spd) - 1;
-	}
-
 	/* wait for device */
 	if (ata_port_online(ap))
 		ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
@@ -5121,6 +5113,9 @@ void ata_dev_init(struct ata_device *dev
 	struct ata_port *ap = dev->ap;
 	unsigned long flags;
 
+	/* SATA spd limit is bound to the first device */
+	ap->sata_spd_limit = ap->hw_sata_spd_limit;
+
 	/* High bits of dev->flags are used to record warm plug
 	 * requests which occur asynchronously.  Synchronize using
 	 * host_set lock.
@@ -5177,7 +5172,7 @@ static void ata_host_init(struct ata_por
 	ap->udma_mask = ent->udma_mask;
 	ap->flags |= ent->host_flags;
 	ap->ops = ent->port_ops;
-	ap->sata_spd_limit = UINT_MAX;
+	ap->hw_sata_spd_limit = UINT_MAX;
 	ap->active_tag = ATA_TAG_POISON;
 	ap->last_ctl = 0xFF;
 
@@ -5340,10 +5335,18 @@ int ata_device_add(const struct ata_prob
 	DPRINTK("probe begin\n");
 	for (i = 0; i < count; i++) {
 		struct ata_port *ap;
+		u32 scontrol;
 		int rc;
 
 		ap = host_set->ports[i];
 
+		/* init sata_spd_limit to the current value */
+		if (ata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
+			int spd = (scontrol >> 4) & 0xf;
+			ap->hw_sata_spd_limit &= (1 << spd) - 1;
+		}
+		ap->sata_spd_limit = ap->hw_sata_spd_limit;
+
 		DPRINTK("ata%u: bus probe begin\n", ap->id);
 		rc = ata_bus_probe(ap);
 		DPRINTK("ata%u: bus probe end\n", ap->id);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 99a78cf..6ab988a 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -480,6 +480,7 @@ struct ata_port {
 	unsigned int		mwdma_mask;
 	unsigned int		udma_mask;
 	unsigned int		cbl;	/* cable type; ATA_CBL_xxx */
+	unsigned int		hw_sata_spd_limit;
 	unsigned int		sata_spd_limit;	/* SATA PHY speed limit */
 
 	/* record runtime error info, protected by host_set lock */
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 07/14] libata-hp-prep: store attached SCSI device
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (9 preceding siblings ...)
  2006-05-11 15:11 ` [PATCH 6/6] sata_sil24: kill ops->tf_read() and use ata_std_noop_check_status() Tejun Heo
@ 2006-05-11 15:11 ` Tejun Heo
  2006-05-11 15:11 ` [PATCH 06/14] libata-hp-prep: implement ap->hw_sata_spd_limit Tejun Heo
                   ` (9 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Add device persistent field dev->sdev and store the attached SCSI
device.  With hotplug, libata needs to know the attached SCSI device
to offline and detach it, but scsi_device_lookup() cannot be used
because libata will reuse SCSI ID numbers - dead but not gone devices
(due to zombie opens, etc...) interfere with the lookup.

dev->sdev doesn't hold reference to the SCSI device.  It's cleared
when the SCSI device goes away.

---

 drivers/scsi/libata-scsi.c |   14 ++++++++++----
 include/linux/libata.h     |    1 +
 2 files changed, 11 insertions(+), 4 deletions(-)

e04f46cf173e4b7f837ac75400eac20e2dd0d057
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 0316bc1..7827844 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -2738,17 +2738,23 @@ void ata_scsi_simulate(struct ata_device
 
 void ata_scsi_scan_host(struct ata_port *ap)
 {
-	struct ata_device *dev;
 	unsigned int i;
 
 	if (ap->flags & ATA_FLAG_DISABLED)
 		return;
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->device[i];
+		struct ata_device *dev = &ap->device[i];
+		struct scsi_device *sdev;
 
-		if (ata_dev_enabled(dev))
-			scsi_scan_target(&ap->host->shost_gendev, 0, i, 0, 0);
+		if (!ata_dev_enabled(dev) || dev->sdev)
+			continue;
+
+		sdev = __scsi_add_device(ap->host, 0, i, 0, NULL);
+		if (!IS_ERR(sdev)) {
+			dev->sdev = sdev;
+			scsi_device_put(sdev);
+		}
 	}
 }
 
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 6ab988a..f4a544e 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -411,6 +411,7 @@ struct ata_device {
 	struct ata_port		*ap;
 	unsigned int		devno;		/* 0 or 1 */
 	unsigned long		flags;		/* ATA_DFLAG_xxx */
+	struct scsi_device	*sdev;		/* attached SCSI device */
 	/* fields above n_sectors are not cleared across device init */
 	u64			n_sectors;	/* size of device, if ATA */
 	unsigned int		class;		/* ATA_DEV_xxx */
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 05/14] libata-hp-prep: use __ata_scsi_find_dev()
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (4 preceding siblings ...)
  2006-05-11 15:11 ` [PATCH 10/14] libata-hp-prep: implement sata_phy_debounce() Tejun Heo
@ 2006-05-11 15:11 ` Tejun Heo
  2006-05-11 15:11 ` [PATCH 5/6] sata_sil24: use sata_phy_debounce() in sil24_hardreset() Tejun Heo
                   ` (14 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Convert direct sdev -> dev lookup to __ata_scsi_find_dev().

---

 drivers/scsi/libata-scsi.c |   16 ++++++----------
 1 files changed, 6 insertions(+), 10 deletions(-)

3a5723bc1fbb5f4869b6dd5598cbeed7cb58f1e2
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index bb40309..0316bc1 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -399,7 +399,7 @@ void ata_dump_status(unsigned id, struct
 int ata_scsi_device_resume(struct scsi_device *sdev)
 {
 	struct ata_port *ap = ata_shost_to_port(sdev->host);
-	struct ata_device *dev = &ap->device[sdev->id];
+	struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
 
 	return ata_device_resume(dev);
 }
@@ -407,7 +407,7 @@ int ata_scsi_device_resume(struct scsi_d
 int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
 {
 	struct ata_port *ap = ata_shost_to_port(sdev->host);
-	struct ata_device *dev = &ap->device[sdev->id];
+	struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
 
 	return ata_device_suspend(dev, state);
 }
@@ -713,19 +713,15 @@ static void ata_scsi_dev_config(struct s
 
 int ata_scsi_slave_config(struct scsi_device *sdev)
 {
+	struct ata_port *ap = ata_shost_to_port(sdev->host);
+	struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
+
 	ata_scsi_sdev_config(sdev);
 
 	blk_queue_max_phys_segments(sdev->request_queue, LIBATA_MAX_PRD);
 
-	if (sdev->id < ATA_MAX_DEVICES) {
-		struct ata_port *ap;
-		struct ata_device *dev;
-
-		ap = ata_shost_to_port(sdev->host);
-		dev = &ap->device[sdev->id];
-
+	if (dev)
 		ata_scsi_dev_config(sdev, dev);
-	}
 
 	return 0;	/* scsi layer doesn't check return value, sigh */
 }
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 10/14] libata-hp-prep: implement sata_phy_debounce()
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (3 preceding siblings ...)
  2006-05-11 15:11 ` [PATCH 2/6] sata_sil: add new constants in preparation for new interrupt handler Tejun Heo
@ 2006-05-11 15:11 ` Tejun Heo
  2006-05-11 15:11 ` [PATCH 05/14] libata-hp-prep: use __ata_scsi_find_dev() Tejun Heo
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

With hotplug, PHY always needs to be debounced before a reset as any
reset might find new devices.  Extract PHY waiting code from
sata_phy_resume() and extend it to include SStatus debouncing.  Note
that sata_phy_debounce() is superset of what used to be done inside
sata_phy_resume().

Two sets of debounce timings are defined and an argument is added to
sata_phy_resume() to select between the two.

---

 drivers/scsi/libata-core.c |  103 ++++++++++++++++++++++++++++++++++++++------
 include/linux/libata.h     |   13 ++++++
 2 files changed, 101 insertions(+), 15 deletions(-)

31e0810e495194fb383ea61ddd059f22449352b0
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 1861373..636f044 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2417,10 +2417,83 @@ err_out:
 	DPRINTK("EXIT\n");
 }
 
-static int sata_phy_resume(struct ata_port *ap)
+/**
+ *	sata_phy_debounce - debounce SATA phy status
+ *	@ap: ATA port to debounce SATA phy status for
+ *	@interval_msec: polling interval in millisecs
+ *	@duration_msec: debounce duration in millisecs
+ *	@timeout_msec: timeout in millisecs
+ *
+ *	Make sure SStatus of @ap reaches stable state, determined by
+ *	holding the same value where DET is not 1 for @duration_msec
+ *	polled every @interval_msec, before @timeout_msec.  Timeout
+ *	constraints the beginning of the stable state.  Because, after
+ *	hot unplugging, DET gets stuck at 1 on some controllers, this
+ *	functions waits until timeout then returns 0 if DET is stable
+ *	at 1.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+int sata_phy_debounce(struct ata_port *ap, unsigned long interval_msec,
+		      unsigned long duration_msec, unsigned long timeout_msec)
+{
+	unsigned long duration = duration_msec * HZ / 1000;
+	unsigned long timeout = jiffies + timeout_msec * HZ / 1000;
+	unsigned long last_jiffies;
+	u32 last, cur;
+	int rc;
+
+	if ((rc = ata_scr_read(ap, SCR_STATUS, &cur)))
+		return rc;
+	cur &= 0xf;
+
+	last = cur;
+	last_jiffies = jiffies;
+
+	while (1) {
+		msleep(interval_msec);
+		if ((rc = ata_scr_read(ap, SCR_STATUS, &cur)))
+			return rc;
+		cur &= 0xf;
+
+		/* DET stable? */
+		if (cur == last) {
+			if (cur == 1 && time_before(jiffies, timeout))
+				continue;
+			if (time_after(jiffies, last_jiffies + duration))
+				return 0;
+			continue;
+		}
+
+		/* unstable, start over */
+		last = cur;
+		last_jiffies = jiffies;
+
+		/* check timeout */
+		if (time_after(jiffies, timeout))
+			return -EBUSY;
+	}
+}
+
+/**
+ *	sata_phy_resume - resume SATA phy
+ *	@ap: ATA port to resume SATA phy for
+ *
+ *	Resume SATA phy of @ap and debounce it.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+int sata_phy_resume(struct ata_port *ap, int quick)
 {
-	unsigned long timeout = jiffies + (HZ * 5);
-	u32 scontrol, sstatus;
+	u32 scontrol;
 	int rc;
 
 	if ((rc = ata_scr_read(ap, SCR_CONTROL, &scontrol)))
@@ -2431,16 +2504,14 @@ static int sata_phy_resume(struct ata_po
 	if ((rc = ata_scr_write(ap, SCR_CONTROL, scontrol)))
 		return rc;
 
-	/* Wait for phy to become ready, if necessary. */
-	do {
-		msleep(200);
-		if ((rc = ata_scr_read(ap, SCR_STATUS, &sstatus)))
-			return rc;
-		if ((sstatus & 0xf) != 1)
-			return 0;
-	} while (time_before(jiffies, timeout));
-
-	return -EBUSY;
+	if (quick)
+		return sata_phy_debounce(ap, ATA_DEBOUNCE_QUICK_INTERVAL,
+					 ATA_DEBOUNCE_QUICK_DURATION,
+					 ATA_DEBOUNCE_QUICK_TIMEOUT);
+	else
+		return sata_phy_debounce(ap, ATA_DEBOUNCE_INTERVAL,
+					 ATA_DEBOUNCE_DURATION,
+					 ATA_DEBOUNCE_TIMEOUT);
 }
 
 /**
@@ -2459,7 +2530,7 @@ static int sata_phy_resume(struct ata_po
 void ata_std_probeinit(struct ata_port *ap)
 {
 	/* resume link */
-	sata_phy_resume(ap);
+	sata_phy_resume(ap, 1);
 
 	/* wait for device */
 	if (ata_port_online(ap))
@@ -2575,7 +2646,7 @@ int sata_std_hardreset(struct ata_port *
 	msleep(1);
 
 	/* bring phy back */
-	sata_phy_resume(ap);
+	sata_phy_resume(ap, 0);
 
 	/* TODO: phy layer with polling, timeouts, etc. */
 	if (ata_port_offline(ap)) {
@@ -5722,6 +5793,8 @@ EXPORT_SYMBOL_GPL(ata_set_sata_spd);
 EXPORT_SYMBOL_GPL(sata_phy_reset);
 EXPORT_SYMBOL_GPL(__sata_phy_reset);
 EXPORT_SYMBOL_GPL(ata_bus_reset);
+EXPORT_SYMBOL_GPL(sata_phy_debounce);
+EXPORT_SYMBOL_GPL(sata_phy_resume);
 EXPORT_SYMBOL_GPL(ata_std_probeinit);
 EXPORT_SYMBOL_GPL(ata_std_softreset);
 EXPORT_SYMBOL_GPL(sata_std_hardreset);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index f4a544e..5c843a8 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -255,6 +255,15 @@ enum {
 	ATA_PROBE_MAX_TRIES	= 3,
 	ATA_EH_RESET_TRIES	= 3,
 	ATA_EH_DEV_TRIES	= 3,
+
+	/* timing constants in millisecs */
+	ATA_DEBOUNCE_QUICK_INTERVAL	= 5,
+	ATA_DEBOUNCE_QUICK_DURATION	= 100,
+	ATA_DEBOUNCE_QUICK_TIMEOUT	= 5000,
+
+	ATA_DEBOUNCE_INTERVAL	= 10,
+	ATA_DEBOUNCE_DURATION	= 500,
+	ATA_DEBOUNCE_TIMEOUT	= 10000,
 };
 
 enum hsm_task_states {
@@ -600,6 +609,10 @@ extern void __sata_phy_reset(struct ata_
 extern void sata_phy_reset(struct ata_port *ap);
 extern void ata_bus_reset(struct ata_port *ap);
 extern int ata_set_sata_spd(struct ata_port *ap);
+extern int sata_phy_debounce(struct ata_port *ap, unsigned long interval_msec,
+			     unsigned long duration_msec,
+			     unsigned long timeout_msec);
+extern int sata_phy_resume(struct ata_port *ap, int quick);
 extern int ata_drive_probe_reset(struct ata_port *ap,
 			ata_probeinit_fn_t probeinit,
 			ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 6/6] sata_sil24: kill ops->tf_read() and use ata_std_noop_check_status()
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (8 preceding siblings ...)
  2006-05-11 15:11 ` [PATCH 04/14] libata-hp-prep: update ata_scsi_find_dev() and friends Tejun Heo
@ 2006-05-11 15:11 ` Tejun Heo
  2006-05-11 15:11 ` [PATCH 07/14] libata-hp-prep: store attached SCSI device Tejun Heo
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:11 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

sil24 doesn't have single TF image.  Result TF's are bound to each
command.  As libata now allows TF-less implementation, kill
ops->tf_read and use ata_std_noop_check_status() for check_status
callbacks.  Result TF is loaded directly from LRAM into qc->result_tf
when needed.

---

 drivers/scsi/sata_sil24.c |   56 ++++++++++++++-------------------------------
 1 files changed, 18 insertions(+), 38 deletions(-)

10b600147b7dc8b2c086281a39d7f23be428e931
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index 72219fa..ef41d5f 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -311,7 +311,6 @@ static struct sil24_cerr_info {
 struct sil24_port_priv {
 	union sil24_cmd_block *cmd_block;	/* 32 cmd blocks */
 	dma_addr_t cmd_block_dma;		/* DMA base addr for them */
-	struct ata_taskfile tf;			/* Cached taskfile registers */
 };
 
 /* ap->host_set->private_data */
@@ -321,10 +320,8 @@ struct sil24_host_priv {
 };
 
 static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev);
-static u8 sil24_check_status(struct ata_port *ap);
 static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
 static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
-static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes);
 static void sil24_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
@@ -378,12 +375,10 @@ static const struct ata_port_operations 
 
 	.dev_config		= sil24_dev_config,
 
-	.check_status		= sil24_check_status,
-	.check_altstatus	= sil24_check_status,
+	.check_status		= ata_noop_check_status,
+	.check_altstatus	= ata_noop_check_status,
 	.dev_select		= ata_noop_dev_select,
 
-	.tf_read		= sil24_tf_read,
-
 	.probe_reset		= sil24_probe_reset,
 
 	.qc_prep		= sil24_qc_prep,
@@ -460,21 +455,15 @@ static void sil24_dev_config(struct ata_
 		writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
 }
 
-static inline void sil24_update_tf(struct ata_port *ap)
+static void sil24_read_tf(struct ata_port *ap, int tag, struct ata_taskfile *tf)
 {
-	struct sil24_port_priv *pp = ap->private_data;
 	void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
-	struct sil24_prb __iomem *prb = port;
+	struct sil24_prb __iomem *prb;
 	u8 fis[6 * 4];
 
-	memcpy_fromio(fis, prb->fis, 6 * 4);
-	ata_tf_from_fis(fis, &pp->tf);
-}
-
-static u8 sil24_check_status(struct ata_port *ap)
-{
-	struct sil24_port_priv *pp = ap->private_data;
-	return pp->tf.command;
+	prb = port + PORT_LRAM + tag * PORT_LRAM_SLOT_SZ;
+	memcpy_fromio(fis, prb->fis, sizeof(fis));
+	ata_tf_from_fis(fis, tf);
 }
 
 static int sil24_scr_map[] = {
@@ -505,12 +494,6 @@ static void sil24_scr_write(struct ata_p
 	}
 }
 
-static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
-{
-	struct sil24_port_priv *pp = ap->private_data;
-	*tf = pp->tf;
-}
-
 static int sil24_init_port(struct ata_port *ap)
 {
 	void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
@@ -533,6 +516,7 @@ static int sil24_softreset(struct ata_po
 	struct sil24_port_priv *pp = ap->private_data;
 	struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
 	dma_addr_t paddr = pp->cmd_block_dma;
+	struct ata_taskfile tf;
 	u32 mask, irq_stat;
 	const char *reason;
 
@@ -572,8 +556,8 @@ static int sil24_softreset(struct ata_po
 		goto err;
 	}
 
-	sil24_update_tf(ap);
-	*class = ata_dev_classify(&pp->tf);
+	sil24_read_tf(ap, 0, &tf);
+	*class = ata_dev_classify(&tf);
 
 	if (*class == ATA_DEV_UNKNOWN)
 		*class = ATA_DEV_NONE;
@@ -622,15 +606,13 @@ static int sil24_hardreset(struct ata_po
 		goto err;
 	}
 
-	if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
-		reason = "device not ready";
-		goto err;
-	}
-
-	/* sil24 doesn't report device class code after hardreset,
-	 * leave *class alone.
+	/* Sil24 doesn't store signature FIS after hardreset, so we
+	 * can't wait for BSY to clear.  Some devices take a long time
+	 * to get ready and those devices will choke if we don't wait
+	 * for BSY clearance here.  Tell libata to perform follow-up
+	 * softreset.
 	 */
-	return 0;
+	return -EAGAIN;
 
  err:
 	ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason);
@@ -817,7 +799,7 @@ static void sil24_error_intr(struct ata_
 		/* record error info */
 		qc = ata_qc_from_tag(ap, ap->active_tag);
 		if (qc) {
-			sil24_update_tf(ap);
+			sil24_read_tf(ap, sil24_tag(qc->tag), &qc->result_tf);
 			qc->err_mask |= err_mask;
 		} else
 			ehi->err_mask |= err_mask;
@@ -835,7 +817,7 @@ static void sil24_error_intr(struct ata_
 static void sil24_finish_qc(struct ata_queued_cmd *qc)
 {
 	if (qc->flags & ATA_QCFLAG_RESULT_TF)
-		sil24_update_tf(qc->ap);
+		sil24_read_tf(qc->ap, sil24_tag(qc->tag), &qc->result_tf);
 }
 
 static inline void sil24_host_intr(struct ata_port *ap)
@@ -955,8 +937,6 @@ static int sil24_port_start(struct ata_p
 	if (!pp)
 		goto err_out;
 
-	pp->tf.command = ATA_DRDY;
-
 	cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL);
 	if (!cb)
 		goto err_out_pp;
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 12/14] libata-hp-prep: implement ata_noop_check_status()
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (17 preceding siblings ...)
  2006-05-11 15:12 ` [PATCH 14/14] libata-hp-prep: implement followup softreset handling Tejun Heo
@ 2006-05-11 15:12 ` Tejun Heo
  2006-05-11 15:12 ` [PATCH 11/14] libata-hp-prep: make ops->tf_read() optional Tejun Heo
  2006-05-11 15:14 ` THIS THREAD IS MESSED UP, PLEASE IGNORE Tejun Heo
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:12 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

As with ops->tf_read, ops->check_status() and ops->check_altstatus()
don't make sense for controllers without single TF image.  As
->check_status() and ->check_altstatus() are deeply integrated into
libata core layer, implement ata_noop_check_status() as a temporary
measure.  This function always returns ATA_DRDY without doing
anything.

In the long term, these IO ops should be made optional and removed
from top level ata_port_operations such that driver implementing
high-level behavior don't have to bother with these.

---

 drivers/scsi/libata-core.c |   19 +++++++++++++++++++
 include/linux/libata.h     |    1 +
 2 files changed, 20 insertions(+), 0 deletions(-)

f404e622e1961647f77ef0d4bf7869e1e1dec70c
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 6d86479..2500854 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -702,6 +702,24 @@ static u64 ata_id_n_sectors(const u16 *i
 }
 
 /**
+ *	ata_noop_check_status - Fake device status reg
+ *	@ap: target port
+ *
+ *	This function performs no actual function and always returns
+ *	ATA_DRDY.
+ *
+ *	May be used as the check_status/altstatus() entry in
+ *	ata_port_operations.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+u8 ata_noop_check_status(struct ata_port *ap)
+{
+	return ATA_DRDY;
+}
+
+/**
  *	ata_noop_dev_select - Select device 0/1 on ATA bus
  *	@ap: ATA channel to manipulate
  *	@device: ATA device (numbered from zero) to select
@@ -5768,6 +5786,7 @@ EXPORT_SYMBOL_GPL(ata_qc_issue_prot);
 EXPORT_SYMBOL_GPL(ata_tf_load);
 EXPORT_SYMBOL_GPL(ata_tf_read);
 EXPORT_SYMBOL_GPL(ata_noop_dev_select);
+EXPORT_SYMBOL_GPL(ata_noop_check_status);
 EXPORT_SYMBOL_GPL(ata_std_dev_select);
 EXPORT_SYMBOL_GPL(ata_tf_to_fis);
 EXPORT_SYMBOL_GPL(ata_tf_from_fis);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 5c843a8..ac8e58c 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -666,6 +666,7 @@ extern void ata_tf_load(struct ata_port 
 extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 extern void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp);
 extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf);
+extern u8 ata_noop_check_status(struct ata_port *ap);
 extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device);
 extern void ata_std_dev_select (struct ata_port *ap, unsigned int device);
 extern u8 ata_check_status(struct ata_port *ap);
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 11/14] libata-hp-prep: make ops->tf_read() optional
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (18 preceding siblings ...)
  2006-05-11 15:12 ` [PATCH 12/14] libata-hp-prep: implement ata_noop_check_status() Tejun Heo
@ 2006-05-11 15:12 ` Tejun Heo
  2006-05-11 15:14 ` THIS THREAD IS MESSED UP, PLEASE IGNORE Tejun Heo
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:12 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Not all controllers have single TF image and ops->tf_read() is
inappropriate for them.  Newly implemented hotplug probing will allow
drivers for such controllers to get rid of ops->tf_read() completely.
Make ops->tf_read() optional in core layer.

---

 drivers/scsi/libata-core.c |    8 +++++---
 drivers/scsi/libata-eh.c   |    3 ++-
 2 files changed, 7 insertions(+), 4 deletions(-)

164a958101ccf3f82b1af1be7dd77d991cd88d65
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 636f044..6d86479 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -4429,14 +4429,15 @@ void ata_qc_complete(struct ata_queued_c
 		if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
 			if (!ata_tag_internal(qc->tag)) {
 				/* always fill result TF for failed qc */
-				ap->ops->tf_read(ap, &qc->result_tf);
+				if (ap->ops->tf_read)
+					ap->ops->tf_read(ap, &qc->result_tf);
 				ata_qc_schedule_eh(qc);
 				return;
 			}
 		}
 
 		/* read result TF if requested */
-		if (qc->flags & ATA_QCFLAG_RESULT_TF)
+		if (ap->ops->tf_read && qc->flags & ATA_QCFLAG_RESULT_TF)
 			ap->ops->tf_read(ap, &qc->result_tf);
 
 		__ata_qc_complete(qc);
@@ -4445,7 +4446,8 @@ void ata_qc_complete(struct ata_queued_c
 			return;
 
 		/* read result TF if failed or requested */
-		if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF)
+		if (ap->ops->tf_read &&
+		    (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF))
 			ap->ops->tf_read(ap, &qc->result_tf);
 
 		__ata_qc_complete(qc);
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index b6268b5..740934b 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -811,7 +811,8 @@ static unsigned int atapi_eh_request_sen
 	memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE);
 
 	/* XXX: why tf_read here? */
-	ap->ops->tf_read(ap, &tf);
+	if (ap->ops->tf_read)
+		ap->ops->tf_read(ap, &tf);
 
 	/* fill these in, for the case where they are -not- overwritten */
 	sense_buf[0] = 0x70;
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 14/14] libata-hp-prep: implement followup softreset handling
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (16 preceding siblings ...)
  2006-05-11 15:12 ` [PATCH 13/14] libata-hp-prep: add prereset() method and implement ata_std_prereset() Tejun Heo
@ 2006-05-11 15:12 ` Tejun Heo
  2006-05-11 15:12 ` [PATCH 12/14] libata-hp-prep: implement ata_noop_check_status() Tejun Heo
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:12 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

In some cases, hardreset must be followed by SRST.

* some controllers can't classify with hardreset
* some controllers can't wait for !BSY after hardreset (LLDD should
  explicitly request followup softreset by returning -EAGAIN)
* (later) PM needs SRST w/ PMP==15 to operate after hardreset

To handle above cases, this patch implements follow-up softreset.
After a hardreset, ata_eh_reset() checks whether any of above
conditions are met and do a follow-up softreset if necessary.

---

 drivers/scsi/libata-eh.c |   58 +++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 52 insertions(+), 6 deletions(-)

413da5b8b08f955db5665d06a497ab7170469363
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index ee046c1..9dfaa66 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1284,16 +1284,28 @@ static void ata_eh_report(struct ata_por
 	}
 }
 
-static int ata_eh_reset(struct ata_port *ap,
+static int ata_eh_followup_srst_needed(int rc, int classify,
+				       const unsigned int *classes)
+{
+	if (rc == -EAGAIN)
+		return 1;
+	if (rc != 0)
+		return 0;
+	if (classify && classes[0] == ATA_DEV_UNKNOWN)
+		return 1;
+	return 0;
+}
+
+static int ata_eh_reset(struct ata_port *ap, int classify,
 			ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
 			ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
 {
 	struct ata_eh_context *ehc = &ap->eh_context;
-	unsigned int classes[ATA_MAX_DEVICES];
+	unsigned int *classes = ehc->classes;
 	int tries = ATA_EH_RESET_TRIES;
 	unsigned int action;
 	ata_reset_fn_t reset;
-	int i, rc;
+	int i, did_followup_srst, rc;
 
 	/* Determine which reset to use and record in ehc->i.action.
 	 * prereset() may examine it to determine what kind of
@@ -1339,10 +1351,44 @@ static int ata_eh_reset(struct ata_port 
 
 	rc = ata_do_reset(ap, reset, classes);
 
+	did_followup_srst = 0;
+	if (reset == hardreset &&
+	    ata_eh_followup_srst_needed(rc, classify, classes)) {
+		/* okay, let's do follow-up softreset */
+		did_followup_srst = 1;
+		reset = softreset;
+
+		if (!reset) {
+			ata_port_printk(ap, KERN_ERR,
+					"follow-up softreset required "
+					"but no softreset avaliable\n");
+			return -EINVAL;
+		}
+
+		ata_eh_about_to_do(ap, ATA_EH_RESET_MASK);
+		rc = ata_do_reset(ap, reset, classes);
+
+		if (rc == 0 && classify &&
+		    classes[0] == ATA_DEV_UNKNOWN) {
+			ata_port_printk(ap, KERN_ERR,
+					"classification failed\n");
+			return -EINVAL;
+		}
+	}
+
 	if (rc && --tries) {
+		const char *type;
+
+		if (reset == softreset) {
+			if (did_followup_srst)
+				type = "follow-up soft";
+			else
+				type = "soft";
+		} else
+			type = "hard";
+
 		ata_port_printk(ap, KERN_WARNING,
-				"%sreset failed, retrying in 5 secs\n",
-				reset == softreset ? "soft" : "hard");
+				"%sreset failed, retrying in 5 secs\n", type);
 		ssleep(5);
 
 		if (reset == hardreset)
@@ -1460,7 +1506,7 @@ static int ata_eh_recover(struct ata_por
 	if (ehc->i.action & ATA_EH_RESET_MASK) {
 		ata_eh_freeze_port(ap);
 
-		rc = ata_eh_reset(ap, prereset, softreset, hardreset,
+		rc = ata_eh_reset(ap, 0, prereset, softreset, hardreset,
 				  postreset);
 		if (rc) {
 			ata_port_printk(ap, KERN_ERR,
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 13/14] libata-hp-prep: add prereset() method and implement ata_std_prereset()
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (15 preceding siblings ...)
  2006-05-11 15:11 ` [PATCH 3/6] sata_sil: new interrupt handler Tejun Heo
@ 2006-05-11 15:12 ` Tejun Heo
  2006-05-11 15:12 ` [PATCH 14/14] libata-hp-prep: implement followup softreset handling Tejun Heo
                   ` (3 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:12 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

With hotplug, every reset might be a probing reset and thus something
similar to probe_init() is needed.  prereset() method is called before
a series of resets to a port and is the counterpart of postreset().
prereset() can also short-circuit probing by returning -ENODEV.

ata_std_prereset() waits for !BSY iff it's boot probe and the port is
online.  The rationales are...

* after hotplugging, BSY clearance is not reliable
* libata can recover from bad resets
* there is no standard way to implement it - some controllers can't
  even do it.

With this behavior, there is a chance that SRST may be issued before
the device enters DI0: Device_idle state which may or may not result
in SRST failure.  However, SATA PM specification states that waiting
for !BSY before issuing SRST is not always possible and thus excludes
the step from device enumeration procedure.  So, all in all, this
should be safe.

If waiting for !BSY before hotplug reset is possible and desirable for
a certain controller, its LLDD is responsible for implementing it.

While at it, this patch unifies function typedef's such that they all
have named arguments.

---

 drivers/scsi/ahci.c         |    3 ++
 drivers/scsi/libata-bmdma.c |   11 ++++++---
 drivers/scsi/libata-core.c  |   42 +++++++++++++++++++++++++++++++++
 drivers/scsi/libata-eh.c    |   54 +++++++++++++++++++++++++++++++++++--------
 drivers/scsi/sata_sil24.c   |    3 ++
 include/linux/libata.h      |   15 +++++++-----
 6 files changed, 106 insertions(+), 22 deletions(-)

561686a7d075c317603fe6aed443895d7ce42c2c
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 9f020cd..f7b550a 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -1017,7 +1017,8 @@ static void ahci_error_handler(struct at
 	}
 
 	/* perform recovery */
-	ata_do_eh(ap, ahci_softreset, ahci_hardreset, ahci_postreset);
+	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset,
+		  ahci_postreset);
 }
 
 static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c
index 741ddc4..db5a975 100644
--- a/drivers/scsi/libata-bmdma.c
+++ b/drivers/scsi/libata-bmdma.c
@@ -695,6 +695,7 @@ void ata_bmdma_thaw(struct ata_port *ap)
 /**
  *	ata_bmdma_drive_eh - Perform EH with given methods for BMDMA controller
  *	@ap: port to handle error for
+ *	@prereset: prereset method (can be NULL)
  *	@softreset: softreset method (can be NULL)
  *	@hardreset: hardreset method (can be NULL)
  *	@postreset: postreset method (can be NULL)
@@ -710,8 +711,9 @@ void ata_bmdma_thaw(struct ata_port *ap)
  *	LOCKING:
  *	Kernel thread context (may sleep)
  */
-void ata_bmdma_drive_eh(struct ata_port *ap, ata_reset_fn_t softreset,
-			ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
+			ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+			ata_postreset_fn_t postreset)
 {
 	struct ata_host_set *host_set = ap->host_set;
 	struct ata_eh_context *ehc = &ap->eh_context;
@@ -759,7 +761,7 @@ void ata_bmdma_drive_eh(struct ata_port 
 		ata_eh_thaw_port(ap);
 
 	/* PIO and DMA engines have been stopped, perform recovery */
-	ata_do_eh(ap, softreset, hardreset, postreset);
+	ata_do_eh(ap, prereset, softreset, hardreset, postreset);
 }
 
 /**
@@ -779,7 +781,8 @@ void ata_bmdma_error_handler(struct ata_
 	if (ata_scr_valid(ap))
 		hardreset = sata_std_hardreset;
 
-	ata_bmdma_drive_eh(ap, ata_std_softreset, hardreset, ata_std_postreset);
+	ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
+			   ata_std_postreset);
 }
 
 /**
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 2500854..7259646 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2533,6 +2533,47 @@ int sata_phy_resume(struct ata_port *ap,
 }
 
 /**
+ *	ata_std_prereset - prepare for reset
+ *	@ap: ATA port to be reset
+ *
+ *	@ap is about to be reset.  Initialize it.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int ata_std_prereset(struct ata_port *ap)
+{
+	int boot_probe = ap->flags & ATA_FLAG_LOADING;
+	int rc;
+
+	/* if we're about to do hardreset, don't bother */
+	if (ap->eh_context.i.action & ATA_EH_HARDRESET)
+		return 0;
+
+	/* resume port */
+	rc = sata_phy_resume(ap, boot_probe);
+	if (rc && rc != -EOPNOTSUPP) {
+		/* phy resume failed, whine but continue */
+		ata_port_printk(ap, KERN_WARNING, "failed to resume link "
+				"for reset (errno=%d)\n", rc);
+	}
+
+	/* Wait for !BSY iff boot probe is in progress and we don't
+	 * know that no device is attached.  The boot probe test is
+	 * necessary because hotplugging doesn't clear BSY in many
+	 * cases.  As we wait for !BSY after resets, this should be
+	 * safe.
+	 */
+	if (boot_probe && !ata_port_offline(ap))
+		ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+	return 0;
+}
+
+/**
  *	ata_std_probeinit - initialize probing
  *	@ap: port to be probed
  *
@@ -5817,6 +5858,7 @@ EXPORT_SYMBOL_GPL(ata_bus_reset);
 EXPORT_SYMBOL_GPL(sata_phy_debounce);
 EXPORT_SYMBOL_GPL(sata_phy_resume);
 EXPORT_SYMBOL_GPL(ata_std_probeinit);
+EXPORT_SYMBOL_GPL(ata_std_prereset);
 EXPORT_SYMBOL_GPL(ata_std_softreset);
 EXPORT_SYMBOL_GPL(sata_std_hardreset);
 EXPORT_SYMBOL_GPL(ata_std_postreset);
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 740934b..ee046c1 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1284,20 +1284,50 @@ static void ata_eh_report(struct ata_por
 	}
 }
 
-static int ata_eh_reset(struct ata_port *ap, ata_reset_fn_t softreset,
+static int ata_eh_reset(struct ata_port *ap,
+			ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
 			ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
 {
 	struct ata_eh_context *ehc = &ap->eh_context;
 	unsigned int classes[ATA_MAX_DEVICES];
 	int tries = ATA_EH_RESET_TRIES;
+	unsigned int action;
 	ata_reset_fn_t reset;
-	int rc;
+	int i, rc;
 
+	/* Determine which reset to use and record in ehc->i.action.
+	 * prereset() may examine it to determine what kind of
+	 * preparation is needed.
+	 */
+	action = ehc->i.action;
+	ehc->i.action &= ~ATA_EH_RESET_MASK;
 	if (softreset && (!hardreset || (!ata_set_sata_spd_needed(ap) &&
-					 !(ehc->i.action & ATA_EH_HARDRESET))))
+					 !(action & ATA_EH_HARDRESET)))) {
+		ehc->i.action |= ATA_EH_SOFTRESET;
 		reset = softreset;
-	else
+	} else {
+		ehc->i.action |= ATA_EH_HARDRESET;
 		reset = hardreset;
+	}
+
+	if (prereset) {
+		rc = prereset(ap);
+
+		/* prereset can short-circuit resetting by returning
+		 * -ENODEV.
+		 */
+		if (rc == -ENODEV) {
+			for (i = 0; i < ATA_MAX_DEVICES; i++)
+				classes[i] = ATA_DEV_NONE;
+			return 0;
+		}
+
+		if (rc) {
+			ata_port_printk(ap, KERN_ERR,
+					"prereset failed (errno=%d)\n", rc);
+			return rc;
+		}
+	}
 
  retry:
 	ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
@@ -1384,6 +1414,7 @@ static int ata_port_nr_enabled(struct at
 /**
  *	ata_eh_recover - recover host port after error
  *	@ap: host port to recover
+ *	@prereset: prereset method (can be NULL)
  *	@softreset: softreset method (can be NULL)
  *	@hardreset: hardreset method (can be NULL)
  *	@postreset: postreset method (can be NULL)
@@ -1400,8 +1431,8 @@ static int ata_port_nr_enabled(struct at
  *	RETURNS:
  *	0 on success, -errno on failure.
  */
-static int ata_eh_recover(struct ata_port *ap, ata_reset_fn_t softreset,
-			  ata_reset_fn_t hardreset,
+static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+			  ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
 			  ata_postreset_fn_t postreset)
 {
 	struct ata_eh_context *ehc = &ap->eh_context;
@@ -1429,7 +1460,8 @@ static int ata_eh_recover(struct ata_por
 	if (ehc->i.action & ATA_EH_RESET_MASK) {
 		ata_eh_freeze_port(ap);
 
-		rc = ata_eh_reset(ap, softreset, hardreset, postreset);
+		rc = ata_eh_reset(ap, prereset, softreset, hardreset,
+				  postreset);
 		if (rc) {
 			ata_port_printk(ap, KERN_ERR,
 					"reset failed, giving up\n");
@@ -1546,6 +1578,7 @@ static void ata_eh_finish(struct ata_por
 /**
  *	ata_do_eh - do standard error handling
  *	@ap: host port to handle error for
+ *	@prereset: prereset method (can be NULL)
  *	@softreset: softreset method (can be NULL)
  *	@hardreset: hardreset method (can be NULL)
  *	@postreset: postreset method (can be NULL)
@@ -1555,11 +1588,12 @@ static void ata_eh_finish(struct ata_por
  *	LOCKING:
  *	Kernel thread context (may sleep).
  */
-void ata_do_eh(struct ata_port *ap, ata_reset_fn_t softreset,
-	       ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
+	       ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+	       ata_postreset_fn_t postreset)
 {
 	ata_eh_autopsy(ap);
 	ata_eh_report(ap);
-	ata_eh_recover(ap, softreset, hardreset, postreset);
+	ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
 	ata_eh_finish(ap);
 }
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index 202d34e..4747047 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -912,7 +912,8 @@ static void sil24_error_handler(struct a
 	}
 
 	/* perform recovery */
-	ata_do_eh(ap, sil24_softreset, sil24_hardreset, ata_std_postreset);
+	ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
+		  ata_std_postreset);
 }
 
 static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
diff --git a/include/linux/libata.h b/include/linux/libata.h
index ac8e58c..9e06d82 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -296,9 +296,10 @@ struct ata_queued_cmd;
 
 /* typedefs */
 typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc);
-typedef void (*ata_probeinit_fn_t)(struct ata_port *);
-typedef int (*ata_reset_fn_t)(struct ata_port *, unsigned int *);
-typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *);
+typedef void (*ata_probeinit_fn_t)(struct ata_port *ap);
+typedef int (*ata_prereset_fn_t)(struct ata_port *ap);
+typedef int (*ata_reset_fn_t)(struct ata_port *ap, unsigned int *classes);
+typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *classes);
 
 struct ata_ioports {
 	unsigned long		cmd_addr;
@@ -618,6 +619,7 @@ extern int ata_drive_probe_reset(struct 
 			ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
 			ata_postreset_fn_t postreset, unsigned int *classes);
 extern void ata_std_probeinit(struct ata_port *ap);
+extern int ata_std_prereset(struct ata_port *ap);
 extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes);
 extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class);
 extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes);
@@ -696,7 +698,7 @@ extern u8   ata_bmdma_status(struct ata_
 extern void ata_bmdma_irq_clear(struct ata_port *ap);
 extern void ata_bmdma_freeze(struct ata_port *ap);
 extern void ata_bmdma_thaw(struct ata_port *ap);
-extern void ata_bmdma_drive_eh(struct ata_port *ap,
+extern void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
 			       ata_reset_fn_t softreset,
 			       ata_reset_fn_t hardreset,
 			       ata_postreset_fn_t postreset);
@@ -774,8 +776,9 @@ extern void ata_eh_thaw_port(struct ata_
 extern void ata_eh_qc_complete(struct ata_queued_cmd *qc);
 extern void ata_eh_qc_retry(struct ata_queued_cmd *qc);
 
-extern void ata_do_eh(struct ata_port *ap, ata_reset_fn_t softreset,
-		      ata_reset_fn_t hardreset, ata_postreset_fn_t postreset);
+extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
+		      ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+		      ata_postreset_fn_t postreset);
 
 /*
  * printk helpers
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: THIS THREAD IS MESSED UP, PLEASE IGNORE
  2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
                   ` (19 preceding siblings ...)
  2006-05-11 15:12 ` [PATCH 11/14] libata-hp-prep: make ops->tf_read() optional Tejun Heo
@ 2006-05-11 15:14 ` Tejun Heo
  20 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:14 UTC (permalink / raw)
  To: Tejun Heo; +Cc: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide

Dang.  Sorry.

-- 
tejun

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 2/6] sata_sil: add new constants in preparation for new interrupt handler
  2006-05-11 15:14 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 (REPOST) Tejun Heo
@ 2006-05-11 15:14 ` Tejun Heo
  0 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-11 15:14 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

sata_sil is about to get a brand new interrupt handler.  Add relevant
constants.

---

 drivers/scsi/sata_sil.c |   24 ++++++++++++++++++++----
 1 files changed, 20 insertions(+), 4 deletions(-)

3d5ca9ae81dfd7cc0220feb7da6b148dad866c0e
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 3e998b7..1c0a751 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -54,6 +54,7 @@ enum {
 	 */
 	SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
 	SIL_FLAG_MOD15WRITE	= (1 << 30),
+
 	SIL_DFL_HOST_FLAGS	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_MMIO,
 
@@ -84,6 +85,20 @@ enum {
 	/* BMDMA/BMDMA2 */
 	SIL_INTR_STEERING	= (1 << 1),
 
+	SIL_DMA_ENABLE		= (1 << 0),  /* DMA run switch */
+	SIL_DMA_RDWR		= (1 << 3),  /* DMA Rd-Wr */
+	SIL_DMA_SATA_IRQ	= (1 << 4),  /* OR of all SATA IRQs */
+	SIL_DMA_ACTIVE		= (1 << 16), /* DMA running */
+	SIL_DMA_ERROR		= (1 << 17), /* PCI bus error */
+	SIL_DMA_COMPLETE	= (1 << 18), /* cmd complete / IRQ pending */
+	SIL_DMA_N_SATA_IRQ	= (1 << 6),  /* SATA_IRQ for the next channel */
+	SIL_DMA_N_ACTIVE	= (1 << 24), /* ACTIVE for the next channel */
+	SIL_DMA_N_ERROR		= (1 << 25), /* ERROR for the next channel */
+	SIL_DMA_N_COMPLETE	= (1 << 26), /* COMPLETE for the next channel */
+
+	/* SIEN */
+	SIL_SIEN_N		= (1 << 16), /* triggered by SError.N */
+
 	/*
 	 * Others
 	 */
@@ -225,6 +240,7 @@ static const struct {
 	unsigned long tf;	/* ATA taskfile register block */
 	unsigned long ctl;	/* ATA control/altstatus register block */
 	unsigned long bmdma;	/* DMA register block */
+	unsigned long bmdma2;	/* DMA register block #2 */
 	unsigned long fifo_cfg;	/* FIFO Valid Byte Count and Control */
 	unsigned long scr;	/* SATA control register block */
 	unsigned long sien;	/* SATA Interrupt Enable register */
@@ -232,10 +248,10 @@ static const struct {
 	unsigned long sfis_cfg;	/* SATA FIS reception config register */
 } sil_port[] = {
 	/* port 0 ... */
-	{ 0x80, 0x8A, 0x00, 0x40, 0x100, 0x148, 0xb4, 0x14c },
-	{ 0xC0, 0xCA, 0x08, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc },
-	{ 0x280, 0x28A, 0x200, 0x240, 0x300, 0x348, 0x2b4, 0x34c },
-	{ 0x2C0, 0x2CA, 0x208, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },
+	{ 0x80, 0x8A, 0x00, 0x10, 0x40, 0x100, 0x148, 0xb4, 0x14c },
+	{ 0xC0, 0xCA, 0x08, 0x18, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc },
+	{ 0x280, 0x28A, 0x200, 0x210, 0x240, 0x300, 0x348, 0x2b4, 0x34c },
+	{ 0x2C0, 0x2CA, 0x208, 0x218, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },
 	/* ... port 3 */
 };
 
-- 
1.2.4



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 2/6] sata_sil: add new constants in preparation for new interrupt handler
  2006-05-19 15:38 [PATCHSET 02/03] prep LLDDs for hotplug support, take 2 Tejun Heo
@ 2006-05-19 15:38 ` Tejun Heo
  0 siblings, 0 replies; 24+ messages in thread
From: Tejun Heo @ 2006-05-19 15:38 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide; +Cc: Tejun Heo

sata_sil is about to get a brand new interrupt handler.  Add relevant
constants.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/sata_sil.c |   24 ++++++++++++++++++++----
 1 files changed, 20 insertions(+), 4 deletions(-)

26c5ba2a53bbce1e60bb065eedf2fe24c706b91f
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index aa63044..e34b9aa 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -54,6 +54,7 @@ enum {
 	 */
 	SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
 	SIL_FLAG_MOD15WRITE	= (1 << 30),
+
 	SIL_DFL_HOST_FLAGS	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_MMIO,
 
@@ -84,6 +85,20 @@ enum {
 	/* BMDMA/BMDMA2 */
 	SIL_INTR_STEERING	= (1 << 1),
 
+	SIL_DMA_ENABLE		= (1 << 0),  /* DMA run switch */
+	SIL_DMA_RDWR		= (1 << 3),  /* DMA Rd-Wr */
+	SIL_DMA_SATA_IRQ	= (1 << 4),  /* OR of all SATA IRQs */
+	SIL_DMA_ACTIVE		= (1 << 16), /* DMA running */
+	SIL_DMA_ERROR		= (1 << 17), /* PCI bus error */
+	SIL_DMA_COMPLETE	= (1 << 18), /* cmd complete / IRQ pending */
+	SIL_DMA_N_SATA_IRQ	= (1 << 6),  /* SATA_IRQ for the next channel */
+	SIL_DMA_N_ACTIVE	= (1 << 24), /* ACTIVE for the next channel */
+	SIL_DMA_N_ERROR		= (1 << 25), /* ERROR for the next channel */
+	SIL_DMA_N_COMPLETE	= (1 << 26), /* COMPLETE for the next channel */
+
+	/* SIEN */
+	SIL_SIEN_N		= (1 << 16), /* triggered by SError.N */
+
 	/*
 	 * Others
 	 */
@@ -225,6 +240,7 @@ static const struct {
 	unsigned long tf;	/* ATA taskfile register block */
 	unsigned long ctl;	/* ATA control/altstatus register block */
 	unsigned long bmdma;	/* DMA register block */
+	unsigned long bmdma2;	/* DMA register block #2 */
 	unsigned long fifo_cfg;	/* FIFO Valid Byte Count and Control */
 	unsigned long scr;	/* SATA control register block */
 	unsigned long sien;	/* SATA Interrupt Enable register */
@@ -232,10 +248,10 @@ static const struct {
 	unsigned long sfis_cfg;	/* SATA FIS reception config register */
 } sil_port[] = {
 	/* port 0 ... */
-	{ 0x80, 0x8A, 0x00, 0x40, 0x100, 0x148, 0xb4, 0x14c },
-	{ 0xC0, 0xCA, 0x08, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc },
-	{ 0x280, 0x28A, 0x200, 0x240, 0x300, 0x348, 0x2b4, 0x34c },
-	{ 0x2C0, 0x2CA, 0x208, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },
+	{ 0x80, 0x8A, 0x00, 0x10, 0x40, 0x100, 0x148, 0xb4, 0x14c },
+	{ 0xC0, 0xCA, 0x08, 0x18, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc },
+	{ 0x280, 0x28A, 0x200, 0x210, 0x240, 0x300, 0x348, 0x2b4, 0x34c },
+	{ 0x2C0, 0x2CA, 0x208, 0x218, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },
 	/* ... port 3 */
 };
 
-- 
1.3.2



^ permalink raw reply related	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2006-05-19 15:38 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-11 15:11 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 Tejun Heo
2006-05-11 15:11 ` [PATCH 01/14] libata-hp-prep: add flags and eh_info/context fields for hotplug Tejun Heo
2006-05-11 15:11 ` [PATCH 1/6] libata: export ata_hsm_move() Tejun Heo
2006-05-11 15:11 ` [PATCH 02/14] libata-hp-prep: implement ata_dev_init() Tejun Heo
2006-05-11 15:11 ` [PATCH 2/6] sata_sil: add new constants in preparation for new interrupt handler Tejun Heo
2006-05-11 15:11 ` [PATCH 10/14] libata-hp-prep: implement sata_phy_debounce() Tejun Heo
2006-05-11 15:11 ` [PATCH 05/14] libata-hp-prep: use __ata_scsi_find_dev() Tejun Heo
2006-05-11 15:11 ` [PATCH 5/6] sata_sil24: use sata_phy_debounce() in sil24_hardreset() Tejun Heo
2006-05-11 15:11 ` [PATCH 08/14] libata-hp-prep: add ata_hotplug_wq Tejun Heo
2006-05-11 15:11 ` [PATCH 04/14] libata-hp-prep: update ata_scsi_find_dev() and friends Tejun Heo
2006-05-11 15:11 ` [PATCH 6/6] sata_sil24: kill ops->tf_read() and use ata_std_noop_check_status() Tejun Heo
2006-05-11 15:11 ` [PATCH 07/14] libata-hp-prep: store attached SCSI device Tejun Heo
2006-05-11 15:11 ` [PATCH 06/14] libata-hp-prep: implement ap->hw_sata_spd_limit Tejun Heo
2006-05-11 15:11 ` [PATCH 03/14] libata-hp-prep: make some ata_device fields persistent Tejun Heo
2006-05-11 15:11 ` [PATCH 4/6] sata_sil24: rename PORT_PRB to PORT_LRAM and add PORT_LRAM_SLOT_SZ Tejun Heo
2006-05-11 15:11 ` [PATCH 09/14] libata-hp-prep: make probing related functions global Tejun Heo
2006-05-11 15:11 ` [PATCH 3/6] sata_sil: new interrupt handler Tejun Heo
2006-05-11 15:12 ` [PATCH 13/14] libata-hp-prep: add prereset() method and implement ata_std_prereset() Tejun Heo
2006-05-11 15:12 ` [PATCH 14/14] libata-hp-prep: implement followup softreset handling Tejun Heo
2006-05-11 15:12 ` [PATCH 12/14] libata-hp-prep: implement ata_noop_check_status() Tejun Heo
2006-05-11 15:12 ` [PATCH 11/14] libata-hp-prep: make ops->tf_read() optional Tejun Heo
2006-05-11 15:14 ` THIS THREAD IS MESSED UP, PLEASE IGNORE Tejun Heo
  -- strict thread matches above, loose matches on Subject: below --
2006-05-11 15:14 [PATCHSET 07/11] prep LLDDs for hotplug support, take 1 (REPOST) Tejun Heo
2006-05-11 15:14 ` [PATCH 2/6] sata_sil: add new constants in preparation for new interrupt handler Tejun Heo
2006-05-19 15:38 [PATCHSET 02/03] prep LLDDs for hotplug support, take 2 Tejun Heo
2006-05-19 15:38 ` [PATCH 2/6] sata_sil: add new constants in preparation for new interrupt handler Tejun Heo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).