linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 10/13] ahci: convert to new probing mechanism and add hotplug support
  2006-05-11 15:32 [PATCHSET 08/11] add hotplug support, take 2 Tejun Heo
@ 2006-05-11 15:32 ` Tejun Heo
  0 siblings, 0 replies; 38+ messages in thread
From: Tejun Heo @ 2006-05-11 15:32 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Convert to new probing mechanism and add hotplug support by enabling
PORT_IRQ_PHYRDY.  Standard EH will do the right thing and schedule
probe after analyzing SError.

---

 drivers/scsi/ahci.c |   30 +++++++++++++-----------------
 1 files changed, 13 insertions(+), 17 deletions(-)

214b9d988fe2db84de1d825d5c57e11ae2ffa28a
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index d977055..ce8b00a 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -136,6 +136,7 @@ enum {
 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
 				  PORT_IRQ_IF_ERR |
 				  PORT_IRQ_CONNECT |
+				  PORT_IRQ_PHYRDY |
 				  PORT_IRQ_UNK_FIS,
 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
 				  PORT_IRQ_TF_ERR |
@@ -200,7 +201,6 @@ static void ahci_scr_write (struct ata_p
 static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
 static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
-static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes);
 static void ahci_irq_clear(struct ata_port *ap);
 static int ahci_port_start(struct ata_port *ap);
 static void ahci_port_stop(struct ata_port *ap);
@@ -239,8 +239,6 @@ static const struct ata_port_operations 
 
 	.tf_read		= ahci_tf_read,
 
-	.probe_reset		= ahci_probe_reset,
-
 	.qc_prep		= ahci_qc_prep,
 	.qc_issue		= ahci_qc_issue,
 
@@ -564,6 +562,17 @@ static int ahci_clo(struct ata_port *ap)
 	return 0;
 }
 
+static int ahci_prereset(struct ata_port *ap)
+{
+	if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
+	    (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
+		/* ATA_BUSY hasn't cleared, so send a CLO */
+		ahci_clo(ap);
+	}
+
+	return ata_std_prereset(ap);
+}
+
 static int ahci_softreset(struct ata_port *ap, unsigned int *class)
 {
 	struct ahci_port_priv *pp = ap->private_data;
@@ -715,19 +724,6 @@ static void ahci_postreset(struct ata_po
 	}
 }
 
-static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes)
-{
-	if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
-	    (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
-		/* ATA_BUSY hasn't cleared, so send a CLO */
-		ahci_clo(ap);
-	}
-
-	return ata_drive_probe_reset(ap, ata_std_probeinit,
-				     ahci_softreset, ahci_hardreset,
-				     ahci_postreset, classes);
-}
-
 static u8 ahci_check_status(struct ata_port *ap)
 {
 	void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
@@ -1018,7 +1014,7 @@ static void ahci_error_handler(struct at
 	}
 
 	/* perform recovery */
-	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset,
+	ata_do_eh(ap, ahci_prereset, ahci_softreset, ahci_hardreset,
 		  ahci_postreset);
 }
 
-- 
1.2.4



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

* [PATCHSET 03/03] add hotplug support, take 3
@ 2006-05-19 15:48 Tejun Heo
  2006-05-19 15:48 ` [PATCH 07/13] libata-hp: implement unload-unplug Tejun Heo
                   ` (12 more replies)
  0 siblings, 13 replies; 38+ messages in thread
From: Tejun Heo @ 2006-05-19 15:48 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide,
	htejun

Hello,

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

This is the third take of add-hotplug-support patchset.  Changes from
the last take[L] are

* Hotplug event is marked with ata_ehi_hotplugged() instead of
  directly setting flags.  The helper also takes care of timestamping
  the event such that spinup waiting time can be calculated.  So,
  LLDDs are required to call ata_ehi_hotplugged() as soon as possible
  once hotplug event is detected.

* ahci is changed to wait for spinup explicitly.  After spinup wait is
  complete, SRST is used to probe the new device.

* ahci hardreset() now clears TF rx area prior to issuing COMRESET to
  avoid finishing prematurely due to the existing TF value.

* sata_sil is changed to issue hardreset after hotplug event.
  COMRESET clears TF on these controllers and make the controllers
  wait for the first D2H reliably.

* sata_sil24 is changed to wait for spinup explicitly.  After spinup
  wait is complete, SRST is used to probe the new device.

This patchset is against

  upstream (8d4ee71ff6de5255ebfdf44fb83419d27bd06368)
  + enforce-default-EH-actions patch [1]
  + scsi_implement_eh-patch [2]
  + prep-for-hotplug-support patchset [3]
  + prep-LLDDs-for-hotplug-support patchset [4]

Thanks.

--
tejun

[T] http://article.gmane.org/gmane.linux.ide/10530
[L] http://article.gmane.org/gmane.linux.ide/10063
[1] http://article.gmane.org/gmane.linux.ide/10317
[2] http://article.gmane.org/gmane.linux.ide/10529
[3] http://article.gmane.org/gmane.linux.ide/10546
[4] http://article.gmane.org/gmane.linux.ide/10573



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

* [PATCH 04/13] libata-hp: implement warmplug
  2006-05-19 15:48 [PATCHSET 03/03] add hotplug support, take 3 Tejun Heo
                   ` (7 preceding siblings ...)
  2006-05-19 15:48 ` [PATCH 08/13] ata_piix: convert ata_piix to new probing mechanism Tejun Heo
@ 2006-05-19 15:48 ` Tejun Heo
  2006-05-19 15:48 ` [PATCH 11/13] sata_sil24: convert to new probing mechanism and add hotplug support Tejun Heo
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 38+ messages in thread
From: Tejun Heo @ 2006-05-19 15:48 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide; +Cc: Tejun Heo

Implement warmplug.  User-initiated unplug can be detected by
hostt->slave_destroy() and plug by transportt->user_scan().  This
patch only implements the two callbacks.  The next function will hook
them.

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

---

 drivers/scsi/libata-core.c |    1 
 drivers/scsi/libata-scsi.c |   89 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/libata.h     |    1 
 3 files changed, 91 insertions(+), 0 deletions(-)

3cdb294a9eb1de1372387163ca93f0798b171e4e
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 7600b5f..48b570c 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -5916,6 +5916,7 @@ EXPORT_SYMBOL_GPL(ata_port_queue_task);
 EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
 EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
 EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
+EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy);
 EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
 EXPORT_SYMBOL_GPL(ata_scsi_release);
 EXPORT_SYMBOL_GPL(ata_host_intr);
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 5a9c08a..0415fd2 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -57,6 +57,8 @@ static struct ata_device * __ata_scsi_fi
 					const struct scsi_device *scsidev);
 static struct ata_device * ata_scsi_find_dev(struct ata_port *ap,
 					    const struct scsi_device *scsidev);
+static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
+			      unsigned int id, unsigned int lun);
 
 
 #define RW_RECOVERY_MPAGE 0x1
@@ -727,6 +729,40 @@ int ata_scsi_slave_config(struct scsi_de
 }
 
 /**
+ *	ata_scsi_slave_destroy - SCSI device is about to be destroyed
+ *	@sdev: SCSI device to be destroyed
+ *
+ *	@sdev is about to be destroyed for hot/warm unplugging.  If
+ *	this unplugging was initiated by libata as indicated by NULL
+ *	dev->sdev, this function doesn't have to do anything.
+ *	Otherwise, SCSI layer initiated warm-unplug is in progress.
+ *	Clear dev->sdev, schedule the device for ATA detach and invoke
+ *	EH.
+ *
+ *	LOCKING:
+ *	Defined by SCSI layer.  We don't really care.
+ */
+void ata_scsi_slave_destroy(struct scsi_device *sdev)
+{
+	struct ata_port *ap = ata_shost_to_port(sdev->host);
+	unsigned long flags;
+	struct ata_device *dev;
+
+	if (!ap->ops->error_handler)
+		return;
+
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	dev = __ata_scsi_find_dev(ap, sdev);
+	if (dev && dev->sdev) {
+		/* SCSI device already in CANCEL state, no need to offline it */
+		dev->sdev = NULL;
+		dev->flags |= ATA_DFLAG_DETACH;
+		ata_port_schedule_eh(ap);
+	}
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+}
+
+/**
  *	ata_scsi_change_queue_depth - SCSI callback for queue depth config
  *	@sdev: SCSI device to configure queue depth for
  *	@queue_depth: new queue depth
@@ -2840,3 +2876,56 @@ void ata_scsi_remove_dev(struct ata_devi
 		scsi_device_put(sdev);
 	}
 }
+
+/**
+ *	ata_scsi_user_scan - indication for user-initiated bus scan
+ *	@shost: SCSI host to scan
+ *	@channel: Channel to scan
+ *	@id: ID to scan
+ *	@lun: LUN to scan
+ *
+ *	This function is called when user explicitly requests bus
+ *	scan.  Set probe pending flag and invoke EH.
+ *
+ *	LOCKING:
+ *	SCSI layer (we don't care)
+ *
+ *	RETURNS:
+ *	Zero.
+ */
+static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
+			      unsigned int id, unsigned int lun)
+{
+	struct ata_port *ap = ata_shost_to_port(shost);
+	unsigned long flags;
+	int rc = 0;
+
+	if (!ap->ops->error_handler)
+		return -EOPNOTSUPP;
+
+	if ((channel != SCAN_WILD_CARD && channel != 0) ||
+	    (lun != SCAN_WILD_CARD && lun != 0))
+		return -EINVAL;
+
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+
+	if (id == SCAN_WILD_CARD) {
+		ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
+		ap->eh_info.action |= ATA_EH_SOFTRESET;
+	} else {
+		struct ata_device *dev = ata_find_dev(ap, id);
+
+		if (dev) {
+			ap->eh_info.probe_mask |= 1 << dev->devno;
+			ap->eh_info.action |= ATA_EH_SOFTRESET;
+		} else
+			rc = -EINVAL;
+	}
+
+	if (rc == 0)
+		ata_port_schedule_eh(ap);
+
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+	return rc;
+}
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 4e7c839..cc67c96 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -723,6 +723,7 @@ extern int ata_std_bios_param(struct scs
 			      struct block_device *bdev,
 			      sector_t capacity, int geom[]);
 extern int ata_scsi_slave_config(struct scsi_device *sdev);
+extern void ata_scsi_slave_destroy(struct scsi_device *sdev);
 extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
 				       int queue_depth);
 extern struct ata_device *ata_dev_pair(struct ata_device *adev);
-- 
1.3.2



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

* [PATCH 09/13] sata_sil: convert to new probing mechanism and add hotplug support
  2006-05-19 15:48 [PATCHSET 03/03] add hotplug support, take 3 Tejun Heo
                   ` (2 preceding siblings ...)
  2006-05-19 15:48 ` [PATCH 05/13] libata-hp: hook warmplug Tejun Heo
@ 2006-05-19 15:48 ` Tejun Heo
  2006-05-19 15:48 ` [PATCH 06/13] libata-hp: implement bootplug Tejun Heo
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 38+ messages in thread
From: Tejun Heo @ 2006-05-19 15:48 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide; +Cc: Tejun Heo

Convert to new probing mechanism and add hotplug support by enabling
SATA IRQ for SError.N, marking ehi for hotplug and scheduling EH on
SATA IRQs.

Sil3112/3512/3114 family of controllers use COMRESET as TF clearing
point and can reliably wait for FIS34 after COMRESET whether the FIS
is the first FIS34 after POR or in response to the COMRESET.  Thus,
setting ATA_FLAG_HRST_TO_RESUME is enough for device detection after
hotplug.

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

---

 drivers/scsi/sata_sil.c |   21 +++++++++++++--------
 1 files changed, 13 insertions(+), 8 deletions(-)

a5ad0f182f2fb6b60a6ac93a25da973759812594
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 96fbeb6..3a9a949 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -56,7 +56,7 @@ enum {
 	SIL_FLAG_MOD15WRITE	= (1 << 30),
 
 	SIL_DFL_HOST_FLAGS	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_MMIO,
+				  ATA_FLAG_MMIO | ATA_FLAG_HRST_TO_RESUME,
 
 	/*
 	 * Controller IDs
@@ -186,7 +186,6 @@ static const struct ata_port_operations 
 	.check_status		= ata_check_status,
 	.exec_command		= ata_exec_command,
 	.dev_select		= ata_std_dev_select,
-	.probe_reset		= ata_std_probe_reset,
 	.post_set_mode		= sil_post_set_mode,
 	.bmdma_setup            = ata_bmdma_setup,
 	.bmdma_start            = ata_bmdma_start,
@@ -343,6 +342,11 @@ static void sil_host_intr(struct ata_por
 	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
 	u8 status;
 
+	if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {
+		ata_ehi_hotplugged(&ap->eh_info);
+		goto freeze;
+	}
+
 	if (unlikely(!qc || qc->tf.ctl & ATA_NIEN))
 		goto freeze;
 
@@ -416,7 +420,7 @@ static irqreturn_t sil_interrupt(int irq
 		if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
 			continue;
 
-		if (!(bmdma2 & SIL_DMA_COMPLETE))
+		if (!(bmdma2 & (SIL_DMA_COMPLETE | SIL_DMA_SATA_IRQ)))
 			continue;
 
 		sil_host_intr(ap, bmdma2);
@@ -433,6 +437,9 @@ static void sil_freeze(struct ata_port *
 	void __iomem *mmio_base = ap->host_set->mmio_base;
 	u32 tmp;
 
+	/* global IRQ mask doesn't block SATA IRQ, turn off explicitly */
+	writel(0, mmio_base + sil_port[ap->port_no].sien);
+
 	/* plug IRQ */
 	tmp = readl(mmio_base + SIL_SYSCFG);
 	tmp |= SIL_MASK_IDE0_INT << ap->port_no;
@@ -449,6 +456,9 @@ static void sil_thaw(struct ata_port *ap
 	ata_chk_status(ap);
 	ata_bmdma_irq_clear(ap);
 
+	/* turn on SATA IRQ */
+	writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);
+
 	/* turn on IRQ */
 	tmp = readl(mmio_base + SIL_SYSCFG);
 	tmp &= ~(SIL_MASK_IDE0_INT << ap->port_no);
@@ -622,11 +632,6 @@ static int sil_init_one (struct pci_dev 
 			       mmio_base + sil_port[2].bmdma);
 	}
 
-	/* mask all SATA phy-related interrupts */
-	/* TODO: unmask bit 6 (SError N bit) for hotplug */
-	for (i = 0; i < probe_ent->n_ports; i++)
-		writel(0, mmio_base + sil_port[i].sien);
-
 	pci_set_master(pdev);
 
 	/* FIXME: check ata_device_add return value */
-- 
1.3.2



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

* [PATCH 05/13] libata-hp: hook warmplug
  2006-05-19 15:48 [PATCHSET 03/03] add hotplug support, take 3 Tejun Heo
  2006-05-19 15:48 ` [PATCH 07/13] libata-hp: implement unload-unplug Tejun Heo
  2006-05-19 15:48 ` [PATCH 02/13] libata-hp: implement hotplug Tejun Heo
@ 2006-05-19 15:48 ` Tejun Heo
  2006-05-19 15:48 ` [PATCH 09/13] sata_sil: convert to new probing mechanism and add hotplug support Tejun Heo
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 38+ messages in thread
From: Tejun Heo @ 2006-05-19 15:48 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide; +Cc: Tejun Heo

Hook transportt->user_scan() and hostt->slave_destroy().

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

---

 drivers/scsi/ahci.c         |    1 +
 drivers/scsi/ata_piix.c     |    1 +
 drivers/scsi/libata-scsi.c  |    1 +
 drivers/scsi/pdc_adma.c     |    1 +
 drivers/scsi/sata_mv.c      |    1 +
 drivers/scsi/sata_nv.c      |    1 +
 drivers/scsi/sata_promise.c |    1 +
 drivers/scsi/sata_qstor.c   |    1 +
 drivers/scsi/sata_sil.c     |    1 +
 drivers/scsi/sata_sil24.c   |    1 +
 drivers/scsi/sata_sis.c     |    1 +
 drivers/scsi/sata_svw.c     |    1 +
 drivers/scsi/sata_sx4.c     |    1 +
 drivers/scsi/sata_uli.c     |    1 +
 drivers/scsi/sata_via.c     |    1 +
 drivers/scsi/sata_vsc.c     |    1 +
 16 files changed, 16 insertions(+), 0 deletions(-)

52246377f6dc7887c1e5ead27312955b74729fd3
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 8493b02..afb3805 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -228,6 +228,7 @@ static struct scsi_host_template ahci_sh
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= AHCI_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 };
 
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index e3184a7..f2d71e7 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -218,6 +218,7 @@ static struct scsi_host_template piix_sh
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 	.resume			= ata_scsi_device_resume,
 	.suspend		= ata_scsi_device_suspend,
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 0415fd2..c2e0bce 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -107,6 +107,7 @@ static const u8 def_control_mpage[CONTRO
 struct scsi_transport_template ata_scsi_transport_template = {
 	.eh_strategy_handler	= ata_scsi_error,
 	.eh_timed_out		= ata_scsi_timed_out,
+	.user_scan		= ata_scsi_user_scan,
 };
 
 
diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c
index a341fa8..eb910e4 100644
--- a/drivers/scsi/pdc_adma.c
+++ b/drivers/scsi/pdc_adma.c
@@ -152,6 +152,7 @@ static struct scsi_host_template adma_at
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= ADMA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 };
 
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
index e6d141d..72db067 100644
--- a/drivers/scsi/sata_mv.c
+++ b/drivers/scsi/sata_mv.c
@@ -387,6 +387,7 @@ static struct scsi_host_template mv_sht 
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= MV_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 };
 
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index 70c5108..2a840f5 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -210,6 +210,7 @@ static struct scsi_host_template nv_sht 
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 };
 
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
index bb00043..9c70018 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -121,6 +121,7 @@ static struct scsi_host_template pdc_ata
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 };
 
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index 54283e0..3fc1003 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -142,6 +142,7 @@ static struct scsi_host_template qs_ata_
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= QS_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 };
 
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index cbced4b..96fbeb6 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -174,6 +174,7 @@ static struct scsi_host_template sil_sht
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 };
 
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index def1378..e92230a 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -367,6 +367,7 @@ static struct scsi_host_template sil24_s
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 };
 
diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c
index 3097821..8297335 100644
--- a/drivers/scsi/sata_sis.c
+++ b/drivers/scsi/sata_sis.c
@@ -96,6 +96,7 @@ static struct scsi_host_template sis_sht
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 };
 
diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c
index d5eb537..b2fe0bc 100644
--- a/drivers/scsi/sata_svw.c
+++ b/drivers/scsi/sata_svw.c
@@ -299,6 +299,7 @@ static struct scsi_host_template k2_sata
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
 #ifdef CONFIG_PPC_OF
 	.proc_info		= k2_sata_proc_info,
 #endif
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
index 70a6954..fb69fc2 100644
--- a/drivers/scsi/sata_sx4.c
+++ b/drivers/scsi/sata_sx4.c
@@ -191,6 +191,7 @@ static struct scsi_host_template pdc_sat
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 };
 
diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c
index 15f81bf..4b4094f 100644
--- a/drivers/scsi/sata_uli.c
+++ b/drivers/scsi/sata_uli.c
@@ -90,6 +90,7 @@ static struct scsi_host_template uli_sht
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 };
 
diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c
index 17aefab..6e3effe 100644
--- a/drivers/scsi/sata_via.c
+++ b/drivers/scsi/sata_via.c
@@ -103,6 +103,7 @@ static struct scsi_host_template svia_sh
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 };
 
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
index 0372be7..d51c8d6 100644
--- a/drivers/scsi/sata_vsc.c
+++ b/drivers/scsi/sata_vsc.c
@@ -279,6 +279,7 @@ static struct scsi_host_template vsc_sat
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 };
 
-- 
1.3.2



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

* [PATCH 03/13] libata-hp: implement SCSI part of hotplug
  2006-05-19 15:48 [PATCHSET 03/03] add hotplug support, take 3 Tejun Heo
                   ` (5 preceding siblings ...)
  2006-05-19 15:48 ` [PATCH 01/13] libata-hp: implement ata_eh_detach_dev() Tejun Heo
@ 2006-05-19 15:48 ` Tejun Heo
  2006-05-19 16:05   ` Jeff Garzik
  2006-05-19 15:48 ` [PATCH 08/13] ata_piix: convert ata_piix to new probing mechanism Tejun Heo
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 38+ messages in thread
From: Tejun Heo @ 2006-05-19 15:48 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide; +Cc: Tejun Heo

Implement SCSI part of hotplug.

This must be done in a separate context as SCSI makes use of EH during
probing.  Unfortunately, SCSI probing fails silently if EH is active.
ata_eh_scsi_hotplug() does its best to avoid such conditions but,
theoretically, it may fail to associate SCSI device to newly found ATA
device; however, the chance is very slim and I haven't experienced any
such event during testing.

Device removal synchronization is somewhat complex but I think I've
got it right and haven't seen it malfunction.

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

---

 drivers/scsi/libata-core.c |    1 +
 drivers/scsi/libata-eh.c   |   70 +++++++++++++++++++++++++++++++++++++++++++-
 drivers/scsi/libata-scsi.c |   59 +++++++++++++++++++++++++++++++++++++
 drivers/scsi/libata.h      |    2 +
 include/linux/libata.h     |    2 +
 5 files changed, 132 insertions(+), 2 deletions(-)

6a1cd6180ac9e13e29446378bd15245c4c7efd5d
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 1809f98..7600b5f 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -5347,6 +5347,7 @@ static void ata_host_init(struct ata_por
 	ap->last_ctl = 0xFF;
 
 	INIT_WORK(&ap->port_task, NULL, NULL);
+	INIT_WORK(&ap->hotplug_task, ata_eh_scsi_hotplug, ap);
 	INIT_LIST_HEAD(&ap->eh_done_q);
 
 	/* set cable type */
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index fff93d9..0ab7d52 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -286,9 +286,13 @@ void ata_scsi_error(struct Scsi_Host *ho
 	/* clean up */
 	spin_lock_irqsave(hs_lock, flags);
 
+	if (ap->flags & ATA_FLAG_SCSI_HOTPLUG)
+		queue_work(ata_hotplug_wq, &ap->hotplug_task);
+
 	if (ap->flags & ATA_FLAG_RECOVERED)
 		ata_port_printk(ap, KERN_INFO, "EH complete\n");
-	ap->flags &= ~ATA_FLAG_RECOVERED;
+
+	ap->flags &= ~(ATA_FLAG_SCSI_HOTPLUG | ATA_FLAG_RECOVERED);
 
 	spin_unlock_irqrestore(hs_lock, flags);
 
@@ -1736,6 +1740,70 @@ static void ata_eh_finish(struct ata_por
 }
 
 /**
+ *	ata_eh_scsi_hotplug - SCSI part of hotplug
+ *	@data: Pointer to ATA port to perform SCSI hotplug on
+ *
+ *	Perform SCSI part of hotplug.  It's executed from a separate
+ *	workqueue after EH completes.  This is necessary because SCSI
+ *	hot plugging requires working EH and hot unplugging is
+ *	synchronized with hot plugging with a mutex.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ */
+void ata_eh_scsi_hotplug(void *data)
+{
+	struct ata_port *ap = data;
+	unsigned long timeout;
+	int i, requeue = 0;
+
+	DPRINTK("ENTER\n");
+
+	/* SCSI hotplug is requested.  EH might still be running and
+	 * we wanna scan the bus after EH is complete; otherwise, SCSI
+	 * scan fails silently.  scsi_block_when_processing_errors()
+	 * cannot be used because we might not have a sdev to wait on.
+	 * Poll for !scsi_host_in_recovery() for 2 secs.
+	 */
+	timeout = jiffies + 2 * HZ;
+	do {
+		if (!scsi_host_in_recovery(ap->host))
+			break;
+		msleep(100);
+	} while (time_before(jiffies, timeout));
+
+	if (scsi_host_in_recovery(ap->host))
+		requeue = 1;
+
+	/* unplug detached devices */
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		struct ata_device *dev = &ap->device[i];
+		unsigned long flags;
+
+		if (!(dev->flags & ATA_DFLAG_DETACHED))
+			continue;
+
+		spin_lock_irqsave(&ap->host_set->lock, flags);
+		dev->flags &= ~ATA_DFLAG_DETACHED;
+		spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+		ata_scsi_remove_dev(dev);
+	}
+
+	/* scan for new ones */
+	ata_scsi_scan_host(ap);
+
+	if (requeue || scsi_host_in_recovery(ap->host)) {
+		/* we might have scanned while EH is active.  Repeat
+		 * scan after a sec.
+		 */
+		queue_delayed_work(ata_hotplug_wq, &ap->hotplug_task, HZ);
+	}
+
+	DPRINTK("EXIT\n");
+}
+
+/**
  *	ata_do_eh - do standard error handling
  *	@ap: host port to handle error for
  *	@prereset: prereset method (can be NULL)
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 5f46b11..5a9c08a 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -2781,3 +2781,62 @@ int ata_scsi_offline_dev(struct ata_devi
 	}
 	return 0;
 }
+
+/**
+ *	ata_scsi_remove_dev - remove attached SCSI device
+ *	@dev: ATA device to remove attached SCSI device for
+ *
+ *	This function is called from ata_eh_scsi_hotplug() and
+ *	responsible for removing the SCSI device attached to @dev.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ */
+void ata_scsi_remove_dev(struct ata_device *dev)
+{
+	struct ata_port *ap = dev->ap;
+	struct scsi_device *sdev;
+	unsigned long flags;
+
+	/* Alas, we need to grab scan_mutex to ensure SCSI device
+	 * state doesn't change underneath us and thus
+	 * scsi_device_get() always succeeds.  The mutex locking can
+	 * be removed if there is __scsi_device_get() interface which
+	 * increments reference counts regardless of device state.
+	 */
+	mutex_lock(&ap->host->scan_mutex);
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+
+	/* clearing dev->sdev is protected by host_set lock */
+	sdev = dev->sdev;
+	dev->sdev = NULL;
+
+	if (sdev) {
+		/* If user initiated unplug races with us, sdev can go
+		 * away underneath us after the host_set lock and
+		 * scan_mutex are released.  Hold onto it.
+		 */
+		if (scsi_device_get(sdev) == 0) {
+			/* The following ensures the attached sdev is
+			 * offline on return from ata_scsi_offline_dev()
+			 * regardless it wins or loses the race
+			 * against this function.
+			 */
+			scsi_device_set_state(sdev, SDEV_OFFLINE);
+		} else {
+			WARN_ON(1);
+			sdev = NULL;
+		}
+	}
+
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+	mutex_unlock(&ap->host->scan_mutex);
+
+	if (sdev) {
+		ata_dev_printk(dev, KERN_INFO, "detaching (SCSI %s)\n",
+			       sdev->sdev_gendev.bus_id);
+
+		scsi_remove_device(sdev);
+		scsi_device_put(sdev);
+	}
+}
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index c8a3350..0176c40 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -76,6 +76,7 @@ extern struct scsi_transport_template at
 
 extern void ata_scsi_scan_host(struct ata_port *ap);
 extern int ata_scsi_offline_dev(struct ata_device *dev);
+extern void ata_scsi_remove_dev(struct ata_device *dev);
 extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
 			       unsigned int buflen);
 
@@ -110,5 +111,6 @@ extern void ata_schedule_scsi_eh(struct 
 extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
+extern void ata_eh_scsi_hotplug(void *data);
 
 #endif /* __LIBATA_H__ */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index df1cf91..4e7c839 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -518,7 +518,7 @@ struct ata_port {
 	struct ata_host_set	*host_set;
 	struct device 		*dev;
 
-	struct work_struct	port_task;
+	struct work_struct	port_task, hotplug_task;
 
 	unsigned int		hsm_task_state;
 
-- 
1.3.2



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

* [PATCH 07/13] libata-hp: implement unload-unplug
  2006-05-19 15:48 [PATCHSET 03/03] add hotplug support, take 3 Tejun Heo
@ 2006-05-19 15:48 ` Tejun Heo
  2006-05-19 16:10   ` Jeff Garzik
  2006-05-19 15:48 ` [PATCH 02/13] libata-hp: implement hotplug Tejun Heo
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 38+ messages in thread
From: Tejun Heo @ 2006-05-19 15:48 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide; +Cc: Tejun Heo

Implement unload unplug - driver unloading / PCI removal via hot
unplug path.  This is done by ata_port_detach() which requests detach
of all devices, schedules EH and wait for it to complete.  EH path is
slightly modified to handle this (e.g. force zero eh_info during
unloading).  With this patch, EH and unloading are properly
synchronized and unloading should be safe under any circumstances.

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

---

 drivers/scsi/ahci.c        |    1 +
 drivers/scsi/libata-core.c |   47 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/scsi/libata-eh.c   |    7 ++++---
 include/linux/libata.h     |    1 +
 4 files changed, 53 insertions(+), 3 deletions(-)

894a291fa186a541ef3eb74d01f0947fb40ad97e
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index afb3805..98fffca 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -1396,6 +1396,7 @@ static void ahci_remove_one (struct pci_
 	for (i = 0; i < host_set->n_ports; i++) {
 		ap = host_set->ports[i];
 
+		ata_port_detach(ap);
 		scsi_remove_host(ap->host);
 	}
 
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index e79d70f..7d5dd9a 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -5595,6 +5595,51 @@ err_free_ret:
 }
 
 /**
+ *	ata_port_detach - Detach ATA port in prepration of device removal
+ *	@ap: ATA port to be detached
+ *
+ *	Detach all ATA devices and associated SCSI devices.  @ap is
+ *	guaranteed to be quiescent on return from this function.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ */
+void ata_port_detach(struct ata_port *ap)
+{
+	unsigned long flags;
+	int i;
+
+	if (!ap->ops->error_handler)
+		return;
+
+	/* tell EH to self-destruct */
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+
+	ap->flags |= ATA_FLAG_UNLOADING;
+	for (i = 0; i < ATA_MAX_DEVICES; i++)
+		ap->device[i].flags |= ATA_DFLAG_DETACH;
+
+	ata_port_schedule_eh(ap);
+
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+	/* wait for EH */
+	while (scsi_host_in_recovery(ap->host))
+		msleep(100);
+
+	/* Flush hotplug task.  The sequence is similar to
+	 * ata_port_flush_task().  ATA_FLAG_UNLOADING prevents further
+	 * queueing of hotplug_task.
+	 */
+	flush_workqueue(ata_hotplug_wq);
+	cancel_delayed_work(&ap->hotplug_task);
+	flush_workqueue(ata_hotplug_wq);
+
+	/* freeze the port */
+	ata_eh_freeze_port(ap);
+}
+
+/**
  *	ata_host_set_remove - PCI layer callback for device removal
  *	@host_set: ATA host set that was removed
  *
@@ -5612,6 +5657,7 @@ void ata_host_set_remove(struct ata_host
 
 	for (i = 0; i < host_set->n_ports; i++) {
 		ap = host_set->ports[i];
+		ata_port_detach(ap);
 		scsi_remove_host(ap->host);
 	}
 
@@ -5886,6 +5932,7 @@ EXPORT_SYMBOL_GPL(sata_deb_timing_before
 EXPORT_SYMBOL_GPL(ata_std_bios_param);
 EXPORT_SYMBOL_GPL(ata_std_ports);
 EXPORT_SYMBOL_GPL(ata_device_add);
+EXPORT_SYMBOL_GPL(ata_port_detach);
 EXPORT_SYMBOL_GPL(ata_host_set_remove);
 EXPORT_SYMBOL_GPL(ata_sg_init);
 EXPORT_SYMBOL_GPL(ata_sg_init_one);
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 5b9aff2..4357465 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -234,7 +234,8 @@ void ata_scsi_error(struct Scsi_Host *ho
 		spin_lock_irqsave(hs_lock, flags);
 
 		memset(&ap->eh_context, 0, sizeof(ap->eh_context));
-		ap->eh_context.i = ap->eh_info;
+		if (!(ap->flags & ATA_FLAG_UNLOADING))
+			ap->eh_context.i = ap->eh_info;
 		memset(&ap->eh_info, 0, sizeof(ap->eh_info));
 
 		ap->flags &= ~ATA_FLAG_EH_PENDING;
@@ -290,7 +291,7 @@ void ata_scsi_error(struct Scsi_Host *ho
 		int bit = fls(ATA_FLAG_LOADING) - 1;
 		clear_bit(bit, &ap->flags);
 		wake_up_bit(&ap->flags, bit);
-	} else {
+	} else if (!(ap->flags & ATA_FLAG_UNLOADING)) {
 		if (ap->flags & ATA_FLAG_SCSI_HOTPLUG)
 			queue_work(ata_hotplug_wq, &ap->hotplug_task);
 		if (ap->flags & ATA_FLAG_RECOVERED)
@@ -1828,7 +1829,7 @@ void ata_do_eh(struct ata_port *ap, ata_
 	       ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
 	       ata_postreset_fn_t postreset)
 {
-	if (!(ap->flags & ATA_FLAG_LOADING)) {
+	if (!(ap->flags & (ATA_FLAG_LOADING | ATA_FLAG_UNLOADING))) {
 		ata_eh_autopsy(ap);
 		ata_eh_report(ap);
 	}
diff --git a/include/linux/libata.h b/include/linux/libata.h
index cc67c96..7090837 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -643,6 +643,7 @@ extern int ata_pci_device_resume(struct 
 extern int ata_pci_clear_simplex(struct pci_dev *pdev);
 #endif /* CONFIG_PCI */
 extern int ata_device_add(const struct ata_probe_ent *ent);
+extern void ata_port_detach(struct ata_port *ap);
 extern void ata_host_set_remove(struct ata_host_set *host_set);
 extern int ata_scsi_detect(struct scsi_host_template *sht);
 extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
-- 
1.3.2



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

* [PATCH 08/13] ata_piix: convert ata_piix to new probing mechanism
  2006-05-19 15:48 [PATCHSET 03/03] add hotplug support, take 3 Tejun Heo
                   ` (6 preceding siblings ...)
  2006-05-19 15:48 ` [PATCH 03/13] libata-hp: implement SCSI part of hotplug Tejun Heo
@ 2006-05-19 15:48 ` Tejun Heo
  2006-05-19 15:48 ` [PATCH 04/13] libata-hp: implement warmplug Tejun Heo
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 38+ messages in thread
From: Tejun Heo @ 2006-05-19 15:48 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide; +Cc: Tejun Heo

Convert ata_piix to new probing mechanism.  Automatic hotplug is not
supported due to hardware limitation (no PHY event interrupt), but
warm plugging works.

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

---

 drivers/scsi/ata_piix.c |   87 +++++++++++++++++------------------------------
 1 files changed, 32 insertions(+), 55 deletions(-)

07c9feece475acfdf45d551da86f13f4db8e35d0
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index f2d71e7..2755bf3 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -146,11 +146,10 @@ struct piix_map_db {
 
 static int piix_init_one (struct pci_dev *pdev,
 				    const struct pci_device_id *ent);
-
-static int piix_pata_probe_reset(struct ata_port *ap, unsigned int *classes);
-static int piix_sata_probe_reset(struct ata_port *ap, unsigned int *classes);
 static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
 static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
+static void piix_pata_error_handler(struct ata_port *ap);
+static void piix_sata_error_handler(struct ata_port *ap);
 
 static unsigned int in_module_init = 1;
 
@@ -235,8 +234,6 @@ static const struct ata_port_operations 
 	.exec_command		= ata_exec_command,
 	.dev_select		= ata_std_dev_select,
 
-	.probe_reset		= piix_pata_probe_reset,
-
 	.bmdma_setup		= ata_bmdma_setup,
 	.bmdma_start		= ata_bmdma_start,
 	.bmdma_stop		= ata_bmdma_stop,
@@ -246,7 +243,7 @@ static const struct ata_port_operations 
 
 	.freeze			= ata_bmdma_freeze,
 	.thaw			= ata_bmdma_thaw,
-	.error_handler		= ata_bmdma_error_handler,
+	.error_handler		= piix_pata_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 
 	.irq_handler		= ata_interrupt,
@@ -266,8 +263,6 @@ static const struct ata_port_operations 
 	.exec_command		= ata_exec_command,
 	.dev_select		= ata_std_dev_select,
 
-	.probe_reset		= piix_sata_probe_reset,
-
 	.bmdma_setup		= ata_bmdma_setup,
 	.bmdma_start		= ata_bmdma_start,
 	.bmdma_stop		= ata_bmdma_stop,
@@ -277,7 +272,7 @@ static const struct ata_port_operations 
 
 	.freeze			= ata_bmdma_freeze,
 	.thaw			= ata_bmdma_thaw,
-	.error_handler		= ata_bmdma_error_handler,
+	.error_handler		= piix_sata_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 
 	.irq_handler		= ata_interrupt,
@@ -462,59 +457,51 @@ cbl40:
 }
 
 /**
- *	piix_pata_probeinit - probeinit for PATA host controller
+ *	piix_pata_prereset - prereset for PATA host controller
  *	@ap: Target port
  *
- *	Probeinit including cable detection.
- *
- *	LOCKING:
- *	None (inherited from caller).
- */
-static void piix_pata_probeinit(struct ata_port *ap)
-{
-	piix_pata_cbl_detect(ap);
-	ata_std_probeinit(ap);
-}
-
-/**
- *	piix_pata_probe_reset - Perform reset on PATA port and classify
- *	@ap: Port to reset
- *	@classes: Resulting classes of attached devices
- *
- *	Reset PATA phy and classify attached devices.
+ *	Prereset including cable detection.
  *
  *	LOCKING:
  *	None (inherited from caller).
  */
-static int piix_pata_probe_reset(struct ata_port *ap, unsigned int *classes)
+static int piix_pata_prereset(struct ata_port *ap)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
 
 	if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->hard_port_no])) {
 		ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
+		ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
 		return 0;
 	}
 
-	return ata_drive_probe_reset(ap, piix_pata_probeinit,
-				     ata_std_softreset, NULL,
-				     ata_std_postreset, classes);
+	piix_pata_cbl_detect(ap);
+
+	return ata_std_prereset(ap);
+}
+
+static void piix_pata_error_handler(struct ata_port *ap)
+{
+	ata_bmdma_drive_eh(ap, piix_pata_prereset, ata_std_softreset, NULL,
+			   ata_std_postreset);
 }
 
 /**
- *	piix_sata_probe - Probe PCI device for present SATA devices
- *	@ap: Port associated with the PCI device we wish to probe
+ *	piix_sata_prereset - prereset for SATA host controller
+ *	@ap: Target port
  *
  *	Reads and configures SATA PCI device's PCI config register
  *	Port Configuration and Status (PCS) to determine port and
- *	device availability.
+ *	device availability.  Return -ENODEV to skip reset if no
+ *	device is present.
  *
  *	LOCKING:
  *	None (inherited from caller).
  *
  *	RETURNS:
- *	Mask of avaliable devices on the port.
+ *	0 if device is present, -ENODEV otherwise.
  */
-static unsigned int piix_sata_probe (struct ata_port *ap)
+static int piix_sata_prereset(struct ata_port *ap)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
 	const unsigned int *map = ap->host_set->private_data;
@@ -556,29 +543,19 @@ static unsigned int piix_sata_probe (str
 	DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n",
 		ap->id, pcs, present_mask);
 
-	return present_mask;
-}
-
-/**
- *	piix_sata_probe_reset - Perform reset on SATA port and classify
- *	@ap: Port to reset
- *	@classes: Resulting classes of attached devices
- *
- *	Reset SATA phy and classify attached devices.
- *
- *	LOCKING:
- *	None (inherited from caller).
- */
-static int piix_sata_probe_reset(struct ata_port *ap, unsigned int *classes)
-{
-	if (!piix_sata_probe(ap)) {
+	if (!present_mask) {
 		ata_port_printk(ap, KERN_INFO, "SATA port has no device.\n");
+		ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
 		return 0;
 	}
 
-	return ata_drive_probe_reset(ap, ata_std_probeinit,
-				     ata_std_softreset, NULL,
-				     ata_std_postreset, classes);
+	return ata_std_prereset(ap);
+}
+
+static void piix_sata_error_handler(struct ata_port *ap)
+{
+	ata_bmdma_drive_eh(ap, piix_sata_prereset, ata_std_softreset, NULL,
+			   ata_std_postreset);
 }
 
 /**
-- 
1.3.2



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

* [PATCH 01/13] libata-hp: implement ata_eh_detach_dev()
  2006-05-19 15:48 [PATCHSET 03/03] add hotplug support, take 3 Tejun Heo
                   ` (4 preceding siblings ...)
  2006-05-19 15:48 ` [PATCH 06/13] libata-hp: implement bootplug Tejun Heo
@ 2006-05-19 15:48 ` Tejun Heo
  2006-05-19 15:48 ` [PATCH 03/13] libata-hp: implement SCSI part of hotplug Tejun Heo
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 38+ messages in thread
From: Tejun Heo @ 2006-05-19 15:48 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide; +Cc: Tejun Heo

Implement ata_eh_detach_dev().  This function is responsible for
detaching an ATA device and offlining the associated SCSI device
atomically so that the detached device is not accessed after ATA
detach is complete.

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

---

 drivers/scsi/libata-eh.c   |   28 ++++++++++++++++++++++++++++
 drivers/scsi/libata-scsi.c |   24 ++++++++++++++++++++++++
 drivers/scsi/libata.h      |    1 +
 3 files changed, 53 insertions(+), 0 deletions(-)

f4a6e5240b58132212fe837bd7d59c71497033fd
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index c76fab0..99222dd 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -629,6 +629,34 @@ void ata_eh_qc_retry(struct ata_queued_c
 }
 
 /**
+ *	ata_eh_detach_dev - detach ATA device
+ *	@dev: ATA device to detach
+ *
+ *	Detach @dev.
+ *
+ *	LOCKING:
+ *	None.
+ */
+static void ata_eh_detach_dev(struct ata_device *dev)
+{
+	struct ata_port *ap = dev->ap;
+	unsigned long flags;
+
+	ata_dev_disable(dev);
+
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+
+	dev->flags &= ~ATA_DFLAG_DETACH;
+
+	if (ata_scsi_offline_dev(dev)) {
+		dev->flags |= ATA_DFLAG_DETACHED;
+		ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
+	}
+
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+}
+
+/**
  *	ata_eh_about_to_do - about to perform eh_action
  *	@ap: target ATA port
  *	@action: action about to be performed
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index d24e091..5f46b11 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -2757,3 +2757,27 @@ void ata_scsi_scan_host(struct ata_port 
 		}
 	}
 }
+
+/**
+ *	ata_scsi_offline_dev - offline attached SCSI device
+ *	@dev: ATA device to offline attached SCSI device for
+ *
+ *	This function is called from ata_eh_hotplug() and responsible
+ *	for taking the SCSI device attached to @dev offline.  This
+ *	function is called with host_set lock which protects dev->sdev
+ *	against clearing.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	1 if attached SCSI device exists, 0 otherwise.
+ */
+int ata_scsi_offline_dev(struct ata_device *dev)
+{
+	if (dev->sdev) {
+		scsi_device_set_state(dev->sdev, SDEV_OFFLINE);
+		return 1;
+	}
+	return 0;
+}
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index d728fd5..c8a3350 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -75,6 +75,7 @@ extern int ata_cmd_ioctl(struct scsi_dev
 extern struct scsi_transport_template ata_scsi_transport_template;
 
 extern void ata_scsi_scan_host(struct ata_port *ap);
+extern int ata_scsi_offline_dev(struct ata_device *dev);
 extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
 			       unsigned int buflen);
 
-- 
1.3.2



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

* [PATCH 02/13] libata-hp: implement hotplug
  2006-05-19 15:48 [PATCHSET 03/03] add hotplug support, take 3 Tejun Heo
  2006-05-19 15:48 ` [PATCH 07/13] libata-hp: implement unload-unplug Tejun Heo
@ 2006-05-19 15:48 ` Tejun Heo
  2006-05-19 16:04   ` Jeff Garzik
  2006-05-19 15:48 ` [PATCH 05/13] libata-hp: hook warmplug Tejun Heo
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 38+ messages in thread
From: Tejun Heo @ 2006-05-19 15:48 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide; +Cc: Tejun Heo

Implement ATA part of hotplug.  To avoid probing broken devices over
and over again, disabled devices are not automatically detached.  They
are detached only if probing is requested for the device or the
associated port is offline.  Also, to avoid infinite probing loop,
Each device is probed only once per EH run.

As SATA PHY status is fragile, devices are detached only after it has
used up its recovery chances unless explicitly requested by LLDD or
user (LLDD may request direct detach if, for example, it supports cold
presence detection).

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

---

 drivers/scsi/libata-eh.c |  123 ++++++++++++++++++++++++++++++++++++++--------
 include/linux/libata.h   |   13 +++++
 2 files changed, 115 insertions(+), 21 deletions(-)

b7c0629960011dae37807041a72d00c3085522d6
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 99222dd..fff93d9 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -895,10 +895,8 @@ static void ata_eh_analyze_serror(struct
 		err_mask |= AC_ERR_SYSTEM;
 		action |= ATA_EH_SOFTRESET;
 	}
-	if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG)) {
-		err_mask |= AC_ERR_ATA_BUS;
-		action |= ATA_EH_HARDRESET;
-	}
+	if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
+		ata_ehi_hotplugged(&ehc->i);
 
 	ehc->i.err_mask |= err_mask;
 	ehc->i.action |= action;
@@ -1444,11 +1442,12 @@ static int ata_eh_reset(struct ata_port 
 	return rc;
 }
 
-static int ata_eh_revalidate(struct ata_port *ap,
-			     struct ata_device **r_failed_dev)
+static int ata_eh_revalidate_and_attach(struct ata_port *ap,
+					struct ata_device **r_failed_dev)
 {
 	struct ata_eh_context *ehc = &ap->eh_context;
 	struct ata_device *dev;
+	unsigned long flags;
 	int i, rc = 0;
 
 	DPRINTK("ENTER\n");
@@ -1470,6 +1469,23 @@ static int ata_eh_revalidate(struct ata_
 				break;
 
 			ehc->i.action &= ~ATA_EH_REVALIDATE;
+		} else if (dev->class == ATA_DEV_UNKNOWN &&
+			   ehc->tries[dev->devno] &&
+			   ata_class_enabled(ehc->classes[dev->devno])) {
+			dev->class = ehc->classes[dev->devno];
+
+			rc = ata_dev_read_id(dev, &dev->class, 1, dev->id);
+			if (rc == 0)
+				rc = ata_dev_configure(dev, 1);
+
+			if (rc) {
+				dev->class = ATA_DEV_UNKNOWN;
+				break;
+			}
+
+			spin_lock_irqsave(&ap->host_set->lock, flags);
+			ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
+			spin_unlock_irqrestore(&ap->host_set->lock, flags);
 		}
 	}
 
@@ -1490,6 +1506,36 @@ static int ata_port_nr_enabled(struct at
 	return cnt;
 }
 
+static int ata_port_nr_vacant(struct ata_port *ap)
+{
+	int i, cnt = 0;
+
+	for (i = 0; i < ATA_MAX_DEVICES; i++)
+		if (ap->device[i].class == ATA_DEV_UNKNOWN)
+			cnt++;
+	return cnt;
+}
+
+static int ata_eh_skip_recovery(struct ata_port *ap)
+{
+	struct ata_eh_context *ehc = &ap->eh_context;
+	int i;
+
+	if (ap->flags & ATA_FLAG_FROZEN || ata_port_nr_enabled(ap))
+		return 0;
+
+	/* skip if class codes for all vacant slots are ATA_DEV_NONE */
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		struct ata_device *dev = &ap->device[i];
+
+		if (dev->class == ATA_DEV_UNKNOWN &&
+		    ehc->classes[dev->devno] != ATA_DEV_NONE)
+			return 0;
+	}
+
+	return 1;
+}
+
 /**
  *	ata_eh_recover - recover host port after error
  *	@ap: host port to recover
@@ -1500,9 +1546,10 @@ static int ata_port_nr_enabled(struct at
  *
  *	This is the alpha and omega, eum and yang, heart and soul of
  *	libata exception handling.  On entry, actions required to
- *	recover each devices are recorded in eh_context.  This
- *	function executes all the operations with appropriate retrials
- *	and fallbacks to resurrect failed devices.
+ *	recover the port and hotplug requests are recorded in
+ *	eh_context.  This function executes all the operations with
+ *	appropriate retrials and fallbacks to resurrect failed
+ *	devices, detach goners and greet newcomers.
  *
  *	LOCKING:
  *	Kernel thread context (may sleep).
@@ -1525,6 +1572,19 @@ static int ata_eh_recover(struct ata_por
 		dev = &ap->device[i];
 
 		ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+
+		/* process hotplug request */
+		if (dev->flags & ATA_DFLAG_DETACH)
+			ata_eh_detach_dev(dev);
+
+		if (!ata_dev_enabled(dev) &&
+		    ((ehc->i.probe_mask & (1 << dev->devno)) &&
+		     !(ehc->did_probe_mask & (1 << dev->devno)))) {
+			ata_eh_detach_dev(dev);
+			ata_dev_init(dev);
+			ehc->did_probe_mask |= (1 << dev->devno);
+			ehc->i.action |= ATA_EH_SOFTRESET;
+		}
 	}
 
  retry:
@@ -1532,15 +1592,18 @@ static int ata_eh_recover(struct ata_por
 	rc = 0;
 
 	/* skip EH if possible. */
-	if (!ata_port_nr_enabled(ap) && !(ap->flags & ATA_FLAG_FROZEN))
+	if (ata_eh_skip_recovery(ap))
 		ehc->i.action = 0;
 
+	for (i = 0; i < ATA_MAX_DEVICES; i++)
+		ehc->classes[i] = ATA_DEV_UNKNOWN;
+
 	/* reset */
 	if (ehc->i.action & ATA_EH_RESET_MASK) {
 		ata_eh_freeze_port(ap);
 
-		rc = ata_eh_reset(ap, 0, prereset, softreset, hardreset,
-				  postreset);
+		rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset,
+				  softreset, hardreset, postreset);
 		if (rc) {
 			ata_port_printk(ap, KERN_ERR,
 					"reset failed, giving up\n");
@@ -1550,8 +1613,8 @@ static int ata_eh_recover(struct ata_por
 		ata_eh_thaw_port(ap);
 	}
 
-	/* revalidate existing devices */
-	rc = ata_eh_revalidate(ap, &dev);
+	/* revalidate existing devices and attach new ones */
+	rc = ata_eh_revalidate_and_attach(ap, &dev);
 	if (rc)
 		goto dev_fail;
 
@@ -1569,6 +1632,8 @@ static int ata_eh_recover(struct ata_por
  dev_fail:
 	switch (rc) {
 	case -ENODEV:
+		/* device missing, schedule probing */
+		ehc->i.probe_mask |= (1 << dev->devno);
 	case -EINVAL:
 		ehc->tries[dev->devno] = 0;
 		break;
@@ -1581,15 +1646,31 @@ static int ata_eh_recover(struct ata_por
 			ehc->tries[dev->devno] = 0;
 	}
 
-	/* disable device if it has used up all its chances */
-	if (ata_dev_enabled(dev) && !ehc->tries[dev->devno])
+	if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
+		/* disable device if it has used up all its chances */
 		ata_dev_disable(dev);
 
-	/* soft didn't work?  be haaaaard */
-	if (ehc->i.flags & ATA_EHI_DID_RESET)
-		ehc->i.action |= ATA_EH_HARDRESET;
-	else
-		ehc->i.action |= ATA_EH_SOFTRESET;
+		/* detach if offline */
+		if (ata_port_offline(ap))
+			ata_eh_detach_dev(dev);
+
+		/* probe if requested */
+		if ((ehc->i.probe_mask & (1 << dev->devno)) &&
+		    !(ehc->did_probe_mask & (1 << dev->devno))) {
+			ata_eh_detach_dev(dev);
+			ata_dev_init(dev);
+
+			ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+			ehc->did_probe_mask |= (1 << dev->devno);
+			ehc->i.action |= ATA_EH_SOFTRESET;
+		}
+	} else {
+		/* soft didn't work?  be haaaaard */
+		if (ehc->i.flags & ATA_EHI_DID_RESET)
+			ehc->i.action |= ATA_EH_HARDRESET;
+		else
+			ehc->i.action |= ATA_EH_SOFTRESET;
+	}
 
 	if (ata_port_nr_enabled(ap)) {
 		ata_port_printk(ap, KERN_WARNING, "failed to recover some "
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 5a382bf..df1cf91 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -813,6 +813,19 @@ #define ata_ehi_clear_desc(ehi) do { \
 	(ehi)->desc_len = 0; \
 } while (0)
 
+static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
+{
+	if (ehi->flags & ATA_EHI_HOTPLUGGED)
+		return;
+
+	ehi->flags |= ATA_EHI_HOTPLUGGED;
+	ehi->hotplug_timestamp = jiffies;
+
+	ehi->err_mask |= AC_ERR_ATA_BUS;
+	ehi->action |= ATA_EH_SOFTRESET;
+	ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
+}
+
 /*
  * qc helpers
  */
-- 
1.3.2



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

* [PATCH 06/13] libata-hp: implement bootplug
  2006-05-19 15:48 [PATCHSET 03/03] add hotplug support, take 3 Tejun Heo
                   ` (3 preceding siblings ...)
  2006-05-19 15:48 ` [PATCH 09/13] sata_sil: convert to new probing mechanism and add hotplug support Tejun Heo
@ 2006-05-19 15:48 ` Tejun Heo
  2006-05-19 16:09   ` Jeff Garzik
  2006-05-19 15:48 ` [PATCH 01/13] libata-hp: implement ata_eh_detach_dev() Tejun Heo
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 38+ messages in thread
From: Tejun Heo @ 2006-05-19 15:48 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide; +Cc: Tejun Heo

Implement bootplug - boot probing via hotplug path.  While loading,
ata_host_add() simply schedules probing and invokes EH.  After EH
completes, ata_host_add() scans and assicates them with SCSI devices.
EH path is slightly modified to handle this (e.g. no autopsy during
bootplug).  The SCSI part is left in ata_host_add() because it's
shared with legacy path and to keep probing order as before (ATA scan
all ports in host_set then attach all).

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

---

 drivers/scsi/libata-core.c |   58 +++++++++++++++++++++++++++++++++-----------
 drivers/scsi/libata-eh.c   |   29 +++++++++++++++-------
 2 files changed, 63 insertions(+), 24 deletions(-)

a1a36d1a5139134fd75d403d1543706c9993f39b
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 48b570c..e79d70f 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -5395,7 +5395,7 @@ static struct ata_port * ata_host_add(co
 
 	DPRINTK("ENTER\n");
 
-	if (!ent->port_ops->probe_reset &&
+	if (!ent->port_ops->probe_reset && !ent->port_ops->error_handler &&
 	    !(ent->host_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
 		printk(KERN_ERR "ata%u: no reset mechanism available\n",
 		       port_no);
@@ -5423,6 +5423,12 @@ err_out:
 	return NULL;
 }
 
+static int ata_boot_probe_wait(void *dummy)
+{
+	schedule();
+	return 0;
+}
+
 /**
  *	ata_device_add - Register hardware device with ATA and SCSI layers
  *	@ent: Probe information describing hardware device to be registered
@@ -5441,7 +5447,6 @@ err_out:
  *	RETURNS:
  *	Number of ports registered.  Zero on error (no ports registered).
  */
-
 int ata_device_add(const struct ata_probe_ent *ent)
 {
 	unsigned int count = 0, i;
@@ -5518,19 +5523,6 @@ int ata_device_add(const struct ata_prob
 		}
 		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);
-
-		if (rc) {
-			/* FIXME: do something useful here?
-			 * Current libata behavior will
-			 * tear down everything when
-			 * the module is removed
-			 * or the h/w is unplugged.
-			 */
-		}
-
 		rc = scsi_add_host(ap->host, dev);
 		if (rc) {
 			ata_port_printk(ap, KERN_ERR, "scsi_add_host failed\n");
@@ -5540,6 +5532,42 @@ int ata_device_add(const struct ata_prob
 			 * at the very least
 			 */
 		}
+
+		if (!ap->ops->probe_reset) {
+			int bit = fls(ATA_FLAG_LOADING) - 1;
+			unsigned long flags;
+
+			ata_port_probe(ap);
+
+			spin_lock_irqsave(&ap->host_set->lock, flags);
+
+			ap->eh_info.probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+			ap->eh_info.action |= ATA_EH_SOFTRESET;
+
+			set_bit(bit, &ap->flags);
+			ata_port_schedule_eh(ap);
+
+			spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+			wait_on_bit(&ap->flags, bit, ata_boot_probe_wait,
+				    TASK_UNINTERRUPTIBLE);
+
+			while (scsi_host_in_recovery(ap->host))
+				msleep(10);
+		} else {
+			DPRINTK("ata%u: bus probe begin\n", ap->id);
+			rc = ata_bus_probe(ap);
+			DPRINTK("ata%u: bus probe end\n", ap->id);
+
+			if (rc) {
+				/* FIXME: do something useful here?
+				 * Current libata behavior will
+				 * tear down everything when
+				 * the module is removed
+				 * or the h/w is unplugged.
+				 */
+			}
+		}
 	}
 
 	/* probes are done, now scan each port's disk(s) */
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 0ab7d52..5b9aff2 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -286,11 +286,16 @@ void ata_scsi_error(struct Scsi_Host *ho
 	/* clean up */
 	spin_lock_irqsave(hs_lock, flags);
 
-	if (ap->flags & ATA_FLAG_SCSI_HOTPLUG)
-		queue_work(ata_hotplug_wq, &ap->hotplug_task);
-
-	if (ap->flags & ATA_FLAG_RECOVERED)
-		ata_port_printk(ap, KERN_INFO, "EH complete\n");
+	if (ap->flags & ATA_FLAG_LOADING) {
+		int bit = fls(ATA_FLAG_LOADING) - 1;
+		clear_bit(bit, &ap->flags);
+		wake_up_bit(&ap->flags, bit);
+	} else {
+		if (ap->flags & ATA_FLAG_SCSI_HOTPLUG)
+			queue_work(ata_hotplug_wq, &ap->hotplug_task);
+		if (ap->flags & ATA_FLAG_RECOVERED)
+			ata_port_printk(ap, KERN_INFO, "EH complete\n");
+	}
 
 	ap->flags &= ~(ATA_FLAG_SCSI_HOTPLUG | ATA_FLAG_RECOVERED);
 
@@ -1330,6 +1335,7 @@ static int ata_eh_reset(struct ata_port 
 	struct ata_eh_context *ehc = &ap->eh_context;
 	unsigned int *classes = ehc->classes;
 	int tries = ATA_EH_RESET_TRIES;
+	int verbose = !(ap->flags & ATA_FLAG_LOADING);
 	unsigned int action;
 	ata_reset_fn_t reset;
 	int i, did_followup_srst, rc;
@@ -1377,8 +1383,10 @@ static int ata_eh_reset(struct ata_port 
 	}
 
  retry:
-	ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
-			reset == softreset ? "soft" : "hard");
+	/* shut up during boot probing */
+	if (verbose)
+		ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
+				reset == softreset ? "soft" : "hard");
 
 	/* reset */
 	ata_eh_about_to_do(ap, ATA_EH_RESET_MASK);
@@ -1820,8 +1828,11 @@ void ata_do_eh(struct ata_port *ap, ata_
 	       ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
 	       ata_postreset_fn_t postreset)
 {
-	ata_eh_autopsy(ap);
-	ata_eh_report(ap);
+	if (!(ap->flags & ATA_FLAG_LOADING)) {
+		ata_eh_autopsy(ap);
+		ata_eh_report(ap);
+	}
+
 	ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
 	ata_eh_finish(ap);
 }
-- 
1.3.2



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

* [PATCH 12/13] libata-hp: killl ops->probe_reset
  2006-05-19 15:48 [PATCHSET 03/03] add hotplug support, take 3 Tejun Heo
                   ` (11 preceding siblings ...)
  2006-05-19 15:48 ` [PATCH 10/13] ahci: convert to new probing mechanism and add hotplug support Tejun Heo
@ 2006-05-19 15:48 ` Tejun Heo
  12 siblings, 0 replies; 38+ messages in thread
From: Tejun Heo @ 2006-05-19 15:48 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide; +Cc: Tejun Heo

Now that all drivers implementing new EH are converted to new probing
mechanism, ops->probe_reset doesn't have any user.  Kill it.

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

---

 drivers/scsi/libata-core.c |  187 +++-----------------------------------------
 include/linux/libata.h     |    8 --
 2 files changed, 13 insertions(+), 182 deletions(-)

3b19fe8c9fdf29f699b9ecd970031fd1639b9225
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 7d5dd9a..6b9586c 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1494,31 +1494,21 @@ static int ata_bus_probe(struct ata_port
 	down_xfermask = 0;
 
 	/* reset and determine device classes */
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		classes[i] = ATA_DEV_UNKNOWN;
+	ap->ops->phy_reset(ap);
 
-	if (ap->ops->probe_reset) {
-		rc = ap->ops->probe_reset(ap, classes);
-		if (rc) {
-			ata_port_printk(ap, KERN_ERR,
-					"reset failed (errno=%d)\n", rc);
-			return rc;
-		}
-	} else {
-		ap->ops->phy_reset(ap);
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		dev = &ap->device[i];
 
-		for (i = 0; i < ATA_MAX_DEVICES; i++) {
-			if (!(ap->flags & ATA_FLAG_DISABLED))
-				classes[i] = ap->device[i].class;
-			ap->device[i].class = ATA_DEV_UNKNOWN;
-		}
+		if (!(ap->flags & ATA_FLAG_DISABLED) &&
+		    dev->class != ATA_DEV_UNKNOWN)
+			classes[dev->devno] = dev->class;
+		else
+			classes[dev->devno] = ATA_DEV_NONE;
 
-		ata_port_probe(ap);
+		dev->class = ATA_DEV_UNKNOWN;
 	}
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		if (classes[i] == ATA_DEV_UNKNOWN)
-			classes[i] = ATA_DEV_NONE;
+	ata_port_probe(ap);
 
 	/* read IDENTIFY page and configure devices */
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
@@ -2610,37 +2600,11 @@ int ata_std_prereset(struct ata_port *ap
 }
 
 /**
- *	ata_std_probeinit - initialize probing
- *	@ap: port to be probed
- *
- *	@ap is about to be probed.  Initialize it.  This function is
- *	to be used as standard callback for ata_drive_probe_reset().
- *
- *	NOTE!!! Do not use this function as probeinit if a low level
- *	driver implements only hardreset.  Just pass NULL as probeinit
- *	in that case.  Using this function is probably okay but doing
- *	so makes reset sequence different from the original
- *	->phy_reset implementation and Jeff nervous.  :-P
- */
-void ata_std_probeinit(struct ata_port *ap)
-{
-	static const unsigned long deb_timing[] = { 5, 100, 5000 };
-
-	/* resume link */
-	sata_phy_resume(ap, deb_timing);
-
-	/* wait for device */
-	if (ata_port_online(ap))
-		ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
-}
-
-/**
  *	ata_std_softreset - reset host port via ATA SRST
  *	@ap: port to reset
  *	@classes: resulting classes of attached devices
  *
- *	Reset host port using ATA SRST.  This function is to be used
- *	as standard callback for ata_drive_*_reset() functions.
+ *	Reset host port using ATA SRST.
  *
  *	LOCKING:
  *	Kernel thread context (may sleep)
@@ -2695,8 +2659,6 @@ int ata_std_softreset(struct ata_port *a
  *	@class: resulting class of attached device
  *
  *	SATA phy-reset host port using DET bits of SControl register.
- *	This function is to be used as standard callback for
- *	ata_drive_*_reset().
  *
  *	LOCKING:
  *	Kernel thread context (may sleep)
@@ -2775,9 +2737,6 @@ int sata_std_hardreset(struct ata_port *
  *	the device might have been reset more than once using
  *	different reset methods before postreset is invoked.
  *
- *	This function is to be used as standard callback for
- *	ata_drive_*_reset().
- *
  *	LOCKING:
  *	Kernel thread context (may sleep)
  */
@@ -2824,32 +2783,6 @@ void ata_std_postreset(struct ata_port *
 	DPRINTK("EXIT\n");
 }
 
-/**
- *	ata_std_probe_reset - standard probe reset method
- *	@ap: prot to perform probe-reset
- *	@classes: resulting classes of attached devices
- *
- *	The stock off-the-shelf ->probe_reset method.
- *
- *	LOCKING:
- *	Kernel thread context (may sleep)
- *
- *	RETURNS:
- *	0 on success, -errno otherwise.
- */
-int ata_std_probe_reset(struct ata_port *ap, unsigned int *classes)
-{
-	ata_reset_fn_t hardreset;
-
-	hardreset = NULL;
-	if (sata_scr_valid(ap))
-		hardreset = sata_std_hardreset;
-
-	return ata_drive_probe_reset(ap, ata_std_probeinit,
-				     ata_std_softreset, hardreset,
-				     ata_std_postreset, classes);
-}
-
 int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
 		 unsigned int *classes)
 {
@@ -2879,97 +2812,6 @@ int ata_do_reset(struct ata_port *ap, at
 }
 
 /**
- *	ata_drive_probe_reset - Perform probe reset with given methods
- *	@ap: port to reset
- *	@probeinit: probeinit method (can be NULL)
- *	@softreset: softreset method (can be NULL)
- *	@hardreset: hardreset method (can be NULL)
- *	@postreset: postreset method (can be NULL)
- *	@classes: resulting classes of attached devices
- *
- *	Reset the specified port and classify attached devices using
- *	given methods.  This function prefers softreset but tries all
- *	possible reset sequences to reset and classify devices.  This
- *	function is intended to be used for constructing ->probe_reset
- *	callback by low level drivers.
- *
- *	Reset methods should follow the following rules.
- *
- *	- Return 0 on sucess, -errno on failure.
- *	- If classification is supported, fill classes[] with
- *	  recognized class codes.
- *	- If classification is not supported, leave classes[] alone.
- *
- *	LOCKING:
- *	Kernel thread context (may sleep)
- *
- *	RETURNS:
- *	0 on success, -EINVAL if no reset method is avaliable, -ENODEV
- *	if classification fails, and any error code from reset
- *	methods.
- */
-int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit,
-			  ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
-			  ata_postreset_fn_t postreset, unsigned int *classes)
-{
-	int rc = -EINVAL;
-
-	ata_eh_freeze_port(ap);
-
-	if (probeinit)
-		probeinit(ap);
-
-	if (softreset && !sata_set_spd_needed(ap)) {
-		rc = ata_do_reset(ap, softreset, classes);
-		if (rc == 0 && classes[0] != ATA_DEV_UNKNOWN)
-			goto done;
-		ata_port_printk(ap, KERN_INFO, "softreset failed, "
-				"will try hardreset in 5 secs\n");
-		ssleep(5);
-	}
-
-	if (!hardreset)
-		goto done;
-
-	while (1) {
-		rc = ata_do_reset(ap, hardreset, classes);
-		if (rc == 0) {
-			if (classes[0] != ATA_DEV_UNKNOWN)
-				goto done;
-			break;
-		}
-
-		if (sata_down_spd_limit(ap))
-			goto done;
-
-		ata_port_printk(ap, KERN_INFO, "hardreset failed, "
-				"will retry in 5 secs\n");
-		ssleep(5);
-	}
-
-	if (softreset) {
-		ata_port_printk(ap, KERN_INFO,
-				"hardreset succeeded without classification, "
-				"will retry softreset in 5 secs\n");
-		ssleep(5);
-
-		rc = ata_do_reset(ap, softreset, classes);
-	}
-
- done:
-	if (rc == 0) {
-		if (postreset)
-			postreset(ap, classes);
-
-		ata_eh_thaw_port(ap);
-
-		if (classes[0] == ATA_DEV_UNKNOWN)
-			rc = -ENODEV;
-	}
-	return rc;
-}
-
-/**
  *	ata_dev_same_device - Determine whether new ID matches configured device
  *	@dev: device to compare against
  *	@new_class: class of the new device
@@ -5395,7 +5237,7 @@ static struct ata_port * ata_host_add(co
 
 	DPRINTK("ENTER\n");
 
-	if (!ent->port_ops->probe_reset && !ent->port_ops->error_handler &&
+	if (!ent->port_ops->error_handler &&
 	    !(ent->host_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
 		printk(KERN_ERR "ata%u: no reset mechanism available\n",
 		       port_no);
@@ -5533,7 +5375,7 @@ int ata_device_add(const struct ata_prob
 			 */
 		}
 
-		if (!ap->ops->probe_reset) {
+		if (ap->ops->error_handler) {
 			int bit = fls(ATA_FLAG_LOADING) - 1;
 			unsigned long flags;
 
@@ -5973,13 +5815,10 @@ EXPORT_SYMBOL_GPL(sata_phy_resume);
 EXPORT_SYMBOL_GPL(sata_phy_reset);
 EXPORT_SYMBOL_GPL(__sata_phy_reset);
 EXPORT_SYMBOL_GPL(ata_bus_reset);
-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);
-EXPORT_SYMBOL_GPL(ata_std_probe_reset);
-EXPORT_SYMBOL_GPL(ata_drive_probe_reset);
 EXPORT_SYMBOL_GPL(ata_dev_revalidate);
 EXPORT_SYMBOL_GPL(ata_dev_classify);
 EXPORT_SYMBOL_GPL(ata_dev_pair);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 7090837..5b9166b 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -303,7 +303,6 @@ 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 *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);
@@ -549,7 +548,6 @@ struct ata_port_operations {
 
 	void (*phy_reset) (struct ata_port *ap); /* obsolete */
 	void (*set_mode) (struct ata_port *ap);
-	int (*probe_reset) (struct ata_port *ap, unsigned int *classes);
 
 	void (*post_set_mode) (struct ata_port *ap);
 
@@ -622,11 +620,6 @@ extern void ata_bus_reset(struct ata_por
 extern int sata_set_spd(struct ata_port *ap);
 extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param);
 extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param);
-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,
-			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);
@@ -683,7 +676,6 @@ extern void ata_std_dev_select (struct a
 extern u8 ata_check_status(struct ata_port *ap);
 extern u8 ata_altstatus(struct ata_port *ap);
 extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf);
-extern int ata_std_probe_reset(struct ata_port *ap, unsigned int *classes);
 extern int ata_port_start (struct ata_port *ap);
 extern void ata_port_stop (struct ata_port *ap);
 extern void ata_host_stop (struct ata_host_set *host_set);
-- 
1.3.2



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

* [PATCH 11/13] sata_sil24: convert to new probing mechanism and add hotplug support
  2006-05-19 15:48 [PATCHSET 03/03] add hotplug support, take 3 Tejun Heo
                   ` (8 preceding siblings ...)
  2006-05-19 15:48 ` [PATCH 04/13] libata-hp: implement warmplug Tejun Heo
@ 2006-05-19 15:48 ` Tejun Heo
  2006-05-19 15:48 ` [PATCH 13/13] libata-hp: move ata_do_reset() to libata-eh.c Tejun Heo
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 38+ messages in thread
From: Tejun Heo @ 2006-05-19 15:48 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide; +Cc: Tejun Heo

Convert to new probing mechanism and add hotplug support by enabling
PORT_IRQ_PHYRDY_CHG, marking ehi for hotplug and scheduling EH on
PORT_IRQ_PHYRDY_CHG or PORT_IRQ_DEV_XCHG.

Sil3124/32 family of controllers don't have any mechanism to wait for
the first FIS34 after hotplug, so ATA_FLAG_CANT_WAIT_FIS34 is used.

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

---

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

fadd699d06782455ada159e9196d81392def01a0
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index e92230a..a4c1584 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -159,7 +159,8 @@ enum {
 	PORT_IRQ_SDB_NOTIFY	= (1 << 11), /* SDB notify received */
 
 	DEF_PORT_IRQ		= PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |
-				  PORT_IRQ_DEV_XCHG | PORT_IRQ_UNK_FIS,
+				  PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG |
+				  PORT_IRQ_UNK_FIS,
 
 	/* bits[27:16] are unmasked (raw) */
 	PORT_IRQ_RAW_SHIFT	= 16,
@@ -228,7 +229,8 @@ enum {
 	/* host flags */
 	SIL24_COMMON_FLAGS	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-				  ATA_FLAG_NCQ,
+	ATA_FLAG_NCQ | /*ATA_FLAG_HRST_TO_RESUME |*/
+				  ATA_FLAG_CANT_WAIT_FIS34,
 	SIL24_FLAG_PCIX_IRQ_WOC	= (1 << 24), /* IRQ loss errata on PCI-X */
 
 	IRQ_STAT_4PORTS		= 0xf,
@@ -322,7 +324,6 @@ struct sil24_host_priv {
 static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev);
 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 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);
 static void sil24_irq_clear(struct ata_port *ap);
@@ -380,8 +381,6 @@ static const struct ata_port_operations 
 	.check_altstatus	= ata_noop_check_status,
 	.dev_select		= ata_noop_dev_select,
 
-	.probe_reset		= sil24_probe_reset,
-
 	.qc_prep		= sil24_qc_prep,
 	.qc_issue		= sil24_qc_issue,
 
@@ -619,13 +618,6 @@ static int sil24_hardreset(struct ata_po
 	return -EIO;
 }
 
-static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes)
-{
-	return ata_drive_probe_reset(ap, ata_std_probeinit,
-				     sil24_softreset, sil24_hardreset,
-				     ata_std_postreset, classes);
-}
-
 static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
 				 struct sil24_sge *sge)
 {
@@ -756,13 +748,11 @@ static void sil24_error_intr(struct ata_
 
 	ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
 
-	if (irq_stat & PORT_IRQ_DEV_XCHG) {
-		ehi->err_mask |= AC_ERR_ATA_BUS;
-		/* sil24 doesn't recover very well from phy
-		 * disconnection with a softreset.  Force hardreset.
-		 */
-		ehi->action |= ATA_EH_HARDRESET;
-		ata_ehi_push_desc(ehi, ", device_exchanged");
+	if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
+		ata_ehi_hotplugged(ehi);
+		ata_ehi_push_desc(ehi, ", %s",
+			       irq_stat & PORT_IRQ_PHYRDY_CHG ?
+			       "PHY RDY changed" : "device exchanged");
 		freeze = 1;
 	}
 
-- 
1.3.2



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

* [PATCH 13/13] libata-hp: move ata_do_reset() to libata-eh.c
  2006-05-19 15:48 [PATCHSET 03/03] add hotplug support, take 3 Tejun Heo
                   ` (9 preceding siblings ...)
  2006-05-19 15:48 ` [PATCH 11/13] sata_sil24: convert to new probing mechanism and add hotplug support Tejun Heo
@ 2006-05-19 15:48 ` Tejun Heo
  2006-05-19 16:13   ` Jeff Garzik
  2006-05-19 15:48 ` [PATCH 10/13] ahci: convert to new probing mechanism and add hotplug support Tejun Heo
  2006-05-19 15:48 ` [PATCH 12/13] libata-hp: killl ops->probe_reset Tejun Heo
  12 siblings, 1 reply; 38+ messages in thread
From: Tejun Heo @ 2006-05-19 15:48 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide; +Cc: Tejun Heo

With ops->probe_init() gone, no user is left in libata-core.c.  Move
ata_do_reset() to libata-eh.c and make it static.

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

---

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

8e2c3e2ccff15e2d111a3b3f21acd9f864672b4e
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 6b9586c..350df1d 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2783,34 +2783,6 @@ void ata_std_postreset(struct ata_port *
 	DPRINTK("EXIT\n");
 }
 
-int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
-		 unsigned int *classes)
-{
-	int i, rc;
-
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		classes[i] = ATA_DEV_UNKNOWN;
-
-	rc = reset(ap, classes);
-	if (rc)
-		return rc;
-
-	/* If any class isn't ATA_DEV_UNKNOWN, consider classification
-	 * is complete and convert all ATA_DEV_UNKNOWN to
-	 * ATA_DEV_NONE.
-	 */
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		if (classes[i] != ATA_DEV_UNKNOWN)
-			break;
-
-	if (i < ATA_MAX_DEVICES)
-		for (i = 0; i < ATA_MAX_DEVICES; i++)
-			if (classes[i] == ATA_DEV_UNKNOWN)
-				classes[i] = ATA_DEV_NONE;
-
-	return 0;
-}
-
 /**
  *	ata_dev_same_device - Determine whether new ID matches configured device
  *	@dev: device to compare against
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 4357465..b1ac851 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1317,6 +1317,34 @@ static void ata_eh_report(struct ata_por
 	}
 }
 
+static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
+			unsigned int *classes)
+{
+	int i, rc;
+
+	for (i = 0; i < ATA_MAX_DEVICES; i++)
+		classes[i] = ATA_DEV_UNKNOWN;
+
+	rc = reset(ap, classes);
+	if (rc)
+		return rc;
+
+	/* If any class isn't ATA_DEV_UNKNOWN, consider classification
+	 * is complete and convert all ATA_DEV_UNKNOWN to
+	 * ATA_DEV_NONE.
+	 */
+	for (i = 0; i < ATA_MAX_DEVICES; i++)
+		if (classes[i] != ATA_DEV_UNKNOWN)
+			break;
+
+	if (i < ATA_MAX_DEVICES)
+		for (i = 0; i < ATA_MAX_DEVICES; i++)
+			if (classes[i] == ATA_DEV_UNKNOWN)
+				classes[i] = ATA_DEV_NONE;
+
+	return 0;
+}
+
 static int ata_eh_followup_srst_needed(int rc, int classify,
 				       const unsigned int *classes)
 {
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index 0176c40..a954500 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -57,8 +57,6 @@ extern int sata_down_spd_limit(struct at
 extern int sata_set_spd_needed(struct ata_port *ap);
 extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0);
 extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
-extern int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
-			unsigned int *classes);
 extern void ata_qc_free(struct ata_queued_cmd *qc);
 extern void ata_qc_issue(struct ata_queued_cmd *qc);
 extern void __ata_qc_complete(struct ata_queued_cmd *qc);
-- 
1.3.2



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

* [PATCH 10/13] ahci: convert to new probing mechanism and add hotplug support
  2006-05-19 15:48 [PATCHSET 03/03] add hotplug support, take 3 Tejun Heo
                   ` (10 preceding siblings ...)
  2006-05-19 15:48 ` [PATCH 13/13] libata-hp: move ata_do_reset() to libata-eh.c Tejun Heo
@ 2006-05-19 15:48 ` Tejun Heo
  2006-05-19 15:48 ` [PATCH 12/13] libata-hp: killl ops->probe_reset Tejun Heo
  12 siblings, 0 replies; 38+ messages in thread
From: Tejun Heo @ 2006-05-19 15:48 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide; +Cc: Tejun Heo

Convert to new probing mechanism and add hotplug support by enabling
PORT_IRQ_PHYRDY, marking ehi for hotplug and scheduling EH on
CONNECT/PHYRDY interrupts.

Unfortunately, ahci cannot reliably wait for the first FIS34 after
hotplug.  It sometimes succeeds but times out more often than not, so
ATA_FLAG_CANT_WAIT_FIS34 is used.

This patch also fixes ahci_hardreset() such that D2H Register FIS RX
area is cleared before issuing COMRESET.  Without this,
ata_busy_sleep() after COMRESET might prematually finish if the
previous TF contains DRDY && !BSY.

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

---

 drivers/scsi/ahci.c |   47 +++++++++++++++++++++++++++--------------------
 1 files changed, 27 insertions(+), 20 deletions(-)

2d9acc3664dfe9204d745ab8d15d04d075b34355
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 98fffca..2aa9314 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -136,6 +136,7 @@ enum {
 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
 				  PORT_IRQ_IF_ERR |
 				  PORT_IRQ_CONNECT |
+				  PORT_IRQ_PHYRDY |
 				  PORT_IRQ_UNK_FIS,
 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
 				  PORT_IRQ_TF_ERR |
@@ -200,7 +201,6 @@ static void ahci_scr_write (struct ata_p
 static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
 static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
-static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes);
 static void ahci_irq_clear(struct ata_port *ap);
 static int ahci_port_start(struct ata_port *ap);
 static void ahci_port_stop(struct ata_port *ap);
@@ -241,8 +241,6 @@ static const struct ata_port_operations 
 
 	.tf_read		= ahci_tf_read,
 
-	.probe_reset		= ahci_probe_reset,
-
 	.qc_prep		= ahci_qc_prep,
 	.qc_issue		= ahci_qc_issue,
 
@@ -267,7 +265,8 @@ static const struct ata_port_info ahci_p
 	{
 		.sht		= &ahci_sht,
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
+				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+				  ATA_FLAG_CANT_WAIT_FIS34,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &ahci_ops,
@@ -277,6 +276,7 @@ static const struct ata_port_info ahci_p
 		.sht		= &ahci_sht,
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+				  ATA_FLAG_CANT_WAIT_FIS34 |
 				  AHCI_FLAG_RESET_NEEDS_CLO,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
@@ -569,6 +569,17 @@ static int ahci_clo(struct ata_port *ap)
 	return 0;
 }
 
+static int ahci_prereset(struct ata_port *ap)
+{
+	if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
+	    (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
+		/* ATA_BUSY hasn't cleared, so send a CLO */
+		ahci_clo(ap);
+	}
+
+	return ata_std_prereset(ap);
+}
+
 static int ahci_softreset(struct ata_port *ap, unsigned int *class)
 {
 	struct ahci_port_priv *pp = ap->private_data;
@@ -678,12 +689,22 @@ static int ahci_softreset(struct ata_por
 
 static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
 {
+	struct ahci_port_priv *pp = ap->private_data;
+	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+	struct ata_taskfile tf;
 	int rc;
 
 	DPRINTK("ENTER\n");
 
 	ahci_stop_engine(ap);
+
+	/* clear D2H reception area to properly wait for FIS34 */
+	ata_tf_init(ap->device, &tf);
+	tf.command = 0xff;
+	ata_tf_to_fis(&tf, d2h_fis, 0);
+
 	rc = sata_std_hardreset(ap, class);
+
 	ahci_start_engine(ap);
 
 	if (rc == 0 && ata_port_online(ap))
@@ -714,19 +735,6 @@ static void ahci_postreset(struct ata_po
 	}
 }
 
-static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes)
-{
-	if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
-	    (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
-		/* ATA_BUSY hasn't cleared, so send a CLO */
-		ahci_clo(ap);
-	}
-
-	return ata_drive_probe_reset(ap, ata_std_probeinit,
-				     ahci_softreset, ahci_hardreset,
-				     ahci_postreset, classes);
-}
-
 static u8 ahci_check_status(struct ata_port *ap)
 {
 	void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
@@ -839,8 +847,7 @@ static void ahci_error_intr(struct ata_p
 	}
 
 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
-		err_mask |= AC_ERR_ATA_BUS;
-		action |= ATA_EH_SOFTRESET;
+		ata_ehi_hotplugged(ehi);
 		ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
 			"connection status changed" : "PHY RDY changed");
 	}
@@ -1027,7 +1034,7 @@ static void ahci_error_handler(struct at
 	}
 
 	/* perform recovery */
-	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset,
+	ata_do_eh(ap, ahci_prereset, ahci_softreset, ahci_hardreset,
 		  ahci_postreset);
 }
 
-- 
1.3.2



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

* Re: [PATCH 02/13] libata-hp: implement hotplug
  2006-05-19 15:48 ` [PATCH 02/13] libata-hp: implement hotplug Tejun Heo
@ 2006-05-19 16:04   ` Jeff Garzik
  0 siblings, 0 replies; 38+ messages in thread
From: Jeff Garzik @ 2006-05-19 16:04 UTC (permalink / raw)
  To: Tejun Heo; +Cc: mlord, albertcc, alan, axboe, forrest.zhao, linux-ide

Tejun Heo wrote:
> Implement ATA part of hotplug.  To avoid probing broken devices over
> and over again, disabled devices are not automatically detached.  They
> are detached only if probing is requested for the device or the
> associated port is offline.  Also, to avoid infinite probing loop,
> Each device is probed only once per EH run.
> 
> As SATA PHY status is fragile, devices are detached only after it has
> used up its recovery chances unless explicitly requested by LLDD or
> user (LLDD may request direct detach if, for example, it supports cold
> presence detection).
> 
> Signed-off-by: Tejun Heo <htejun@gmail.com>

ACK 1-2



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

* Re: [PATCH 03/13] libata-hp: implement SCSI part of hotplug
  2006-05-19 15:48 ` [PATCH 03/13] libata-hp: implement SCSI part of hotplug Tejun Heo
@ 2006-05-19 16:05   ` Jeff Garzik
  2006-05-23 14:52     ` Tejun Heo
  0 siblings, 1 reply; 38+ messages in thread
From: Jeff Garzik @ 2006-05-19 16:05 UTC (permalink / raw)
  To: Tejun Heo; +Cc: mlord, albertcc, alan, axboe, forrest.zhao, linux-ide

Tejun Heo wrote:
> Implement SCSI part of hotplug.
> 
> This must be done in a separate context as SCSI makes use of EH during
> probing.  Unfortunately, SCSI probing fails silently if EH is active.
> ata_eh_scsi_hotplug() does its best to avoid such conditions but,
> theoretically, it may fail to associate SCSI device to newly found ATA
> device; however, the chance is very slim and I haven't experienced any
> such event during testing.
> 
> Device removal synchronization is somewhat complex but I think I've
> got it right and haven't seen it malfunction.
> 
> Signed-off-by: Tejun Heo <htejun@gmail.com>
> 
> ---
> 
>  drivers/scsi/libata-core.c |    1 +
>  drivers/scsi/libata-eh.c   |   70 +++++++++++++++++++++++++++++++++++++++++++-
>  drivers/scsi/libata-scsi.c |   59 +++++++++++++++++++++++++++++++++++++
>  drivers/scsi/libata.h      |    2 +
>  include/linux/libata.h     |    2 +
>  5 files changed, 132 insertions(+), 2 deletions(-)
> 
> 6a1cd6180ac9e13e29446378bd15245c4c7efd5d
> diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
> index 1809f98..7600b5f 100644
> --- a/drivers/scsi/libata-core.c
> +++ b/drivers/scsi/libata-core.c
> @@ -5347,6 +5347,7 @@ static void ata_host_init(struct ata_por
>  	ap->last_ctl = 0xFF;
>  
>  	INIT_WORK(&ap->port_task, NULL, NULL);
> +	INIT_WORK(&ap->hotplug_task, ata_eh_scsi_hotplug, ap);
>  	INIT_LIST_HEAD(&ap->eh_done_q);
>  
>  	/* set cable type */
> diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
> index fff93d9..0ab7d52 100644
> --- a/drivers/scsi/libata-eh.c
> +++ b/drivers/scsi/libata-eh.c
> @@ -286,9 +286,13 @@ void ata_scsi_error(struct Scsi_Host *ho
>  	/* clean up */
>  	spin_lock_irqsave(hs_lock, flags);
>  
> +	if (ap->flags & ATA_FLAG_SCSI_HOTPLUG)
> +		queue_work(ata_hotplug_wq, &ap->hotplug_task);
> +
>  	if (ap->flags & ATA_FLAG_RECOVERED)
>  		ata_port_printk(ap, KERN_INFO, "EH complete\n");
> -	ap->flags &= ~ATA_FLAG_RECOVERED;
> +
> +	ap->flags &= ~(ATA_FLAG_SCSI_HOTPLUG | ATA_FLAG_RECOVERED);
>  
>  	spin_unlock_irqrestore(hs_lock, flags);
>  
> @@ -1736,6 +1740,70 @@ static void ata_eh_finish(struct ata_por
>  }
>  
>  /**
> + *	ata_eh_scsi_hotplug - SCSI part of hotplug
> + *	@data: Pointer to ATA port to perform SCSI hotplug on
> + *
> + *	Perform SCSI part of hotplug.  It's executed from a separate
> + *	workqueue after EH completes.  This is necessary because SCSI
> + *	hot plugging requires working EH and hot unplugging is
> + *	synchronized with hot plugging with a mutex.
> + *
> + *	LOCKING:
> + *	Kernel thread context (may sleep).
> + */
> +void ata_eh_scsi_hotplug(void *data)

Would prefer ata_eh_scsi_hotplug() to be in libata-scsi.  Otherwise ACK.

	Jeff




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

* Re: [PATCH 06/13] libata-hp: implement bootplug
  2006-05-19 15:48 ` [PATCH 06/13] libata-hp: implement bootplug Tejun Heo
@ 2006-05-19 16:09   ` Jeff Garzik
  0 siblings, 0 replies; 38+ messages in thread
From: Jeff Garzik @ 2006-05-19 16:09 UTC (permalink / raw)
  To: Tejun Heo; +Cc: mlord, albertcc, alan, axboe, forrest.zhao, linux-ide

Tejun Heo wrote:
> Implement bootplug - boot probing via hotplug path.  While loading,
> ata_host_add() simply schedules probing and invokes EH.  After EH
> completes, ata_host_add() scans and assicates them with SCSI devices.
> EH path is slightly modified to handle this (e.g. no autopsy during
> bootplug).  The SCSI part is left in ata_host_add() because it's
> shared with legacy path and to keep probing order as before (ATA scan
> all ports in host_set then attach all).
> 
> Signed-off-by: Tejun Heo <htejun@gmail.com>

ACK 4-6



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

* Re: [PATCH 07/13] libata-hp: implement unload-unplug
  2006-05-19 15:48 ` [PATCH 07/13] libata-hp: implement unload-unplug Tejun Heo
@ 2006-05-19 16:10   ` Jeff Garzik
  2006-05-23 14:53     ` Tejun Heo
  0 siblings, 1 reply; 38+ messages in thread
From: Jeff Garzik @ 2006-05-19 16:10 UTC (permalink / raw)
  To: Tejun Heo; +Cc: mlord, albertcc, alan, axboe, forrest.zhao, linux-ide

Tejun Heo wrote:
> Implement unload unplug - driver unloading / PCI removal via hot
> unplug path.  This is done by ata_port_detach() which requests detach
> of all devices, schedules EH and wait for it to complete.  EH path is
> slightly modified to handle this (e.g. force zero eh_info during
> unloading).  With this patch, EH and unloading are properly
> synchronized and unloading should be safe under any circumstances.
> 
> Signed-off-by: Tejun Heo <htejun@gmail.com>
> 
> ---
> 
>  drivers/scsi/ahci.c        |    1 +
>  drivers/scsi/libata-core.c |   47 ++++++++++++++++++++++++++++++++++++++++++++
>  drivers/scsi/libata-eh.c   |    7 ++++---
>  include/linux/libata.h     |    1 +
>  4 files changed, 53 insertions(+), 3 deletions(-)
> 
> 894a291fa186a541ef3eb74d01f0947fb40ad97e
> diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
> index afb3805..98fffca 100644
> --- a/drivers/scsi/ahci.c
> +++ b/drivers/scsi/ahci.c
> @@ -1396,6 +1396,7 @@ static void ahci_remove_one (struct pci_
>  	for (i = 0; i < host_set->n_ports; i++) {
>  		ap = host_set->ports[i];
>  
> +		ata_port_detach(ap);
>  		scsi_remove_host(ap->host);

Seems like a nice cleanup would be to move scsi_remove_host() into 
ata_port_detach() ?  It would be nice to remove that tidbit of SCSI host 
management from the ->remove() hook in various drivers (mostly ahci, 
sata_sil24, and libata-core).

ACK.

	Jeff




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

* Re: [PATCH 13/13] libata-hp: move ata_do_reset() to libata-eh.c
  2006-05-19 15:48 ` [PATCH 13/13] libata-hp: move ata_do_reset() to libata-eh.c Tejun Heo
@ 2006-05-19 16:13   ` Jeff Garzik
  2006-05-19 20:13     ` [PATCH 0/7] sata_mv: assorted fixes Mark Lord
  0 siblings, 1 reply; 38+ messages in thread
From: Jeff Garzik @ 2006-05-19 16:13 UTC (permalink / raw)
  To: Tejun Heo; +Cc: mlord, albertcc, alan, axboe, forrest.zhao, linux-ide

Tejun Heo wrote:
> With ops->probe_init() gone, no user is left in libata-core.c.  Move
> ata_do_reset() to libata-eh.c and make it static.
> 
> Signed-off-by: Tejun Heo <htejun@gmail.com>

ACK patches 8-13



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

* [PATCH 0/7] sata_mv: assorted fixes
  2006-05-19 16:13   ` Jeff Garzik
@ 2006-05-19 20:13     ` Mark Lord
  2006-05-19 20:21       ` [PATCH 1/7] sata_mv: prevent unnecessary double-resets Mark Lord
                         ` (6 more replies)
  0 siblings, 7 replies; 38+ messages in thread
From: Mark Lord @ 2006-05-19 20:13 UTC (permalink / raw)
  To: Jeff Garzik, linux-ide

The following seven patches contain various fixes and cleanups for
the libata Marvell SATA driver sata_mv.c taken from my internal tree.

These fixes have reportedly solved many problems for a number of
different users.  The driver is still HIGHLY EXPERIMENTAL, at least until
more people exercise this latest driver and report on success/issues.

Cheers

Mark

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

* [PATCH 1/7] sata_mv: prevent unnecessary double-resets
  2006-05-19 20:13     ` [PATCH 0/7] sata_mv: assorted fixes Mark Lord
@ 2006-05-19 20:21       ` Mark Lord
  2006-05-19 20:24       ` [PATCH 2/7] sata_mv: deal with interrupt coalescing interrupts Mark Lord
                         ` (5 subsequent siblings)
  6 siblings, 0 replies; 38+ messages in thread
From: Mark Lord @ 2006-05-19 20:21 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linux-ide

The mv_err_intr() function is invoked from the driver's interrupt handler,
as well as from the timeout function.  This patch prevents it from triggering
a one-after-the-other double reset of the controller when invoked
from the timeout function.

This also adds a check for a timeout race condition that has been observed
to occur with this driver in earlier kernels.  This should not be needed,
in theory, but in practice it has caught bugs.  Maybe nuke it at a later date.

Signed-off-by: Mark Lord <liml@rtr.ca>

---

--- linux/drivers/scsi/sata_mv.c	2006-05-19 15:00:20.000000000 -0400
+++ linux/drivers/scsi/sata_mv.c	2006-05-19 14:58:51.000000000 -0400
@@ -1291,6 +1291,7 @@
 /**
  *      mv_err_intr - Handle error interrupts on the port
  *      @ap: ATA channel to manipulate
+ *      @reset_allowed: bool: 0 == don't trigger from reset here
  *
  *      In most cases, just clear the interrupt and move on.  However,
  *      some cases require an eDMA reset, which is done right before
@@ -1301,7 +1302,7 @@
  *      LOCKING:
  *      Inherited from caller.
  */
-static void mv_err_intr(struct ata_port *ap)
+static void mv_err_intr(struct ata_port *ap, int reset_allowed)
 {
 	void __iomem *port_mmio = mv_ap_base(ap);
 	u32 edma_err_cause, serr = 0;
@@ -1323,9 +1324,8 @@
 	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
 
 	/* check for fatal here and recover if needed */
-	if (EDMA_ERR_FATAL & edma_err_cause) {
+	if (reset_allowed && (EDMA_ERR_FATAL & edma_err_cause))
 		mv_stop_and_reset(ap);
-	}
 }
 
 /**
@@ -1406,7 +1406,7 @@
 			shift++;	/* skip bit 8 in the HC Main IRQ reg */
 		}
 		if ((PORT0_ERR << shift) & relevant) {
-			mv_err_intr(ap);
+			mv_err_intr(ap, 1);
 			err_mask |= AC_ERR_OTHER;
 			handled = 1;
 		}
@@ -2033,11 +2033,14 @@
 	       ap->host_set->mmio_base, ap, qc, qc->scsicmd,
 	       &qc->scsicmd->cmnd);
 
-	mv_err_intr(ap);
+	mv_err_intr(ap, 0);
 	mv_stop_and_reset(ap);
 
-	qc->err_mask |= AC_ERR_TIMEOUT;
-	ata_eh_qc_complete(qc);
+	WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
+	if (qc->flags & ATA_QCFLAG_ACTIVE) {
+		qc->err_mask |= AC_ERR_TIMEOUT;
+		ata_eh_qc_complete(qc);
+	}
 }
 
 /**

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

* [PATCH 2/7] sata_mv: deal with interrupt coalescing interrupts
  2006-05-19 20:13     ` [PATCH 0/7] sata_mv: assorted fixes Mark Lord
  2006-05-19 20:21       ` [PATCH 1/7] sata_mv: prevent unnecessary double-resets Mark Lord
@ 2006-05-19 20:24       ` Mark Lord
  2006-05-20  4:32         ` Jeff Garzik
  2006-05-19 20:29       ` [PATCH 3/7] sata_mv: chip initialization fixes Mark Lord
                         ` (4 subsequent siblings)
  6 siblings, 1 reply; 38+ messages in thread
From: Mark Lord @ 2006-05-19 20:24 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linux-ide

In some systems, it is possible that the BIOS may have enabled interrupt coalescing
for the Marvell controllers which support it.  This patch adds code to detect/ack
interrupts from the chip's coalescing (combing) logic.

Signed-off-by: Mark Lord <liml@rtr.ca>

---

--- linux/drivers/scsi/sata_mv.c	2006-05-19 15:05:40.000000000 -0400
+++ linux/drivers/scsi/sata_mv.c	2006-05-19 15:17:19.000000000 -0400
@@ -50,6 +50,12 @@
 
 	MV_PCI_REG_BASE		= 0,
 	MV_IRQ_COAL_REG_BASE	= 0x18000,	/* 6xxx part only */
+	MV_IRQ_COAL_CAUSE		= (MV_IRQ_COAL_REG_BASE + 0x08),
+	MV_IRQ_COAL_CAUSE_LO		= (MV_IRQ_COAL_REG_BASE + 0x88),
+	MV_IRQ_COAL_CAUSE_HI		= (MV_IRQ_COAL_REG_BASE + 0x8c),
+	MV_IRQ_COAL_THRESHOLD		= (MV_IRQ_COAL_REG_BASE + 0xcc),
+	MV_IRQ_COAL_TIME_THRESHOLD	= (MV_IRQ_COAL_REG_BASE + 0xd0),
+
 	MV_SATAHC0_REG_BASE	= 0x20000,
 	MV_FLASH_CTL		= 0x1046c,
 	MV_GPIO_PORT_CTL	= 0x104f0,
@@ -1448,6 +1454,7 @@
 	struct ata_host_set *host_set = dev_instance;
 	unsigned int hc, handled = 0, n_hcs;
 	void __iomem *mmio = host_set->mmio_base;
+	struct mv_host_priv *hpriv;
 	u32 irq_stat;
 
 	irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
@@ -1469,6 +1476,17 @@
 			handled++;
 		}
 	}
+
+	hpriv = host_set->private_data;
+	if (IS_60XX(hpriv)) {
+		/* deal with the interrupt coalescing bits */
+		if (irq_stat & (TRAN_LO_DONE | TRAN_HI_DONE | PORTS_0_7_COAL_DONE)) {
+			writelfl(0, mmio + MV_IRQ_COAL_CAUSE_LO);
+			writelfl(0, mmio + MV_IRQ_COAL_CAUSE_HI);
+			writelfl(0, mmio + MV_IRQ_COAL_CAUSE);
+		}
+	}
+
 	if (PCI_ERR & irq_stat) {
 		printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n",
 		       readl(mmio + PCI_IRQ_CAUSE_OFS));

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

* [PATCH 3/7] sata_mv: chip initialization fixes
  2006-05-19 20:13     ` [PATCH 0/7] sata_mv: assorted fixes Mark Lord
  2006-05-19 20:21       ` [PATCH 1/7] sata_mv: prevent unnecessary double-resets Mark Lord
  2006-05-19 20:24       ` [PATCH 2/7] sata_mv: deal with interrupt coalescing interrupts Mark Lord
@ 2006-05-19 20:29       ` Mark Lord
  2006-05-19 20:33       ` [PATCH 4/7] sata_mv: spurious interrupt workaround Mark Lord
                         ` (3 subsequent siblings)
  6 siblings, 0 replies; 38+ messages in thread
From: Mark Lord @ 2006-05-19 20:29 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linux-ide

The interface control register of the 60xx (and later) Marvell chip
requires certain bits to always be set when writing to it.  These bits
incorrectly read-back as zeros, so the pattern must be ORed in
with each write of the register.  Also, bit 12 should NOT be set
(note that Marvell's own driver also had bit-12 wrong here).

While we're at it, we also now do pci_set_master() in the init code.

Signed-off-by: Mark Lord <liml@rtr.ca>

---
--- linux/drivers/scsi/sata_mv.c	2006-05-19 15:32:32.000000000 -0400
+++ linux/drivers/scsi/sata_mv.c	2006-05-19 15:39:27.000000000 -0400
@@ -1885,7 +1885,8 @@
 
 	if (IS_60XX(hpriv)) {
 		u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
-		ifctl |= (1 << 12) | (1 << 7);
+		ifctl |= (1 << 7);		/* enable gen2i speed */
+		ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
 		writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
 	}
 
@@ -2252,7 +2253,8 @@
 			void __iomem *port_mmio = mv_port_base(mmio, port);
 
 			u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
-			ifctl |= (1 << 12);
+			ifctl |= (1 << 7);		/* enable gen2i speed */
+			ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
 			writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
 		}
 
@@ -2353,6 +2355,7 @@
 	if (rc) {
 		return rc;
 	}
+	pci_set_master(pdev);
 
 	rc = pci_request_regions(pdev, DRV_NAME);
 	if (rc) {

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

* [PATCH 4/7] sata_mv: spurious interrupt workaround
  2006-05-19 20:13     ` [PATCH 0/7] sata_mv: assorted fixes Mark Lord
                         ` (2 preceding siblings ...)
  2006-05-19 20:29       ` [PATCH 3/7] sata_mv: chip initialization fixes Mark Lord
@ 2006-05-19 20:33       ` Mark Lord
  2006-05-19 20:36       ` [PATCH 5/7] sata_mv: remove local copy of queue indexes Mark Lord
                         ` (2 subsequent siblings)
  6 siblings, 0 replies; 38+ messages in thread
From: Mark Lord @ 2006-05-19 20:33 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linux-ide

The 60xx chips, and possibly others, incorrectly assert DEV_IRQ interrupts
on a regular basis.  The cause of this is under investigation (by me and
in theory by Marvell also), but regardless we do need to deal with these events.

This patch tidies up some interrupt handler code, and ensures that we ignore
DEV_IRQ interrupts when the drive still  has ATA_BUSY asserted.

Signed-off-by: Mark Lord <liml@rtr.ca>

---
--- linux/drivers/scsi/sata_mv.c	2006-05-19 15:39:27.000000000 -0400
+++ linux/drivers/scsi/sata_mv.c	2006-05-19 15:40:46.000000000 -0400
@@ -1380,12 +1380,12 @@
 		struct ata_port *ap = host_set->ports[port];
 		struct mv_port_priv *pp = ap->private_data;
 
-		hard_port = port & MV_PORT_MASK;	/* range 0-3 */
+		hard_port = mv_hardport_from_port(port); /* range 0..3 */
 		handled = 0;	/* ensure ata_status is set if handled++ */
 
 		/* Note that DEV_IRQ might happen spuriously during EDMA,
-		 * and should be ignored in such cases.  We could mask it,
-		 * but it's pretty rare and may not be worth the overhead.
+		 * and should be ignored in such cases.
+		 * The cause of this is still under investigation.
 		 */ 
 		if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
 			/* EDMA: check for response queue interrupt */
@@ -1399,6 +1399,11 @@
 				ata_status = readb((void __iomem *)
 					   ap->ioaddr.status_addr);
 				handled = 1;
+				/* ignore spurious intr if drive still BUSY */
+				if (ata_status & ATA_BUSY) {
+					ata_status = 0;
+					handled = 0;
+				}
 			}
 		}
 

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

* [PATCH 5/7] sata_mv: remove local copy of queue indexes
  2006-05-19 20:13     ` [PATCH 0/7] sata_mv: assorted fixes Mark Lord
                         ` (3 preceding siblings ...)
  2006-05-19 20:33       ` [PATCH 4/7] sata_mv: spurious interrupt workaround Mark Lord
@ 2006-05-19 20:36       ` Mark Lord
  2006-05-19 20:40       ` [PATCH 6/7] sata_mv: endian fix Mark Lord
  2006-05-19 20:41       ` [PATCH 7/7] sata_mv: version bump Mark Lord
  6 siblings, 0 replies; 38+ messages in thread
From: Mark Lord @ 2006-05-19 20:36 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linux-ide

The driver currently keeps local copies of the hardware request/response queue indexes.
But it expends significant effort ensuring consistency between the two views,
and still gets it wrong after an error or reset occurs.

This patch removes the local copies, in favour of just accessing the hardware
whenever we need them.  Eventually this may need to be tweaked again for NCQ,
but for now this works and solves problems some users were seeing.

Signed-off-by: Mark Lord <liml@rtr.ca>

---
--- linux/drivers/scsi/sata_mv.c	2006-05-19 15:40:46.000000000 -0400
+++ linux/drivers/scsi/sata_mv.c	2006-05-19 15:44:11.000000000 -0400
@@ -308,9 +308,6 @@
 	dma_addr_t		crpb_dma;
 	struct mv_sg		*sg_tbl;
 	dma_addr_t		sg_tbl_dma;
-
-	unsigned		req_producer;		/* cp of req_in_ptr */
-	unsigned		rsp_consumer;		/* cp of rsp_out_ptr */
 	u32			pp_flags;
 };
 
@@ -943,8 +940,6 @@
 	writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK,
 		 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
 
-	pp->req_producer = pp->rsp_consumer = 0;
-
 	/* Don't turn on EDMA here...do it before DMA commands only.  Else
 	 * we'll be unable to send non-data, PIO, etc due to restricted access
 	 * to shadow regs.
@@ -1028,10 +1023,9 @@
 	}
 }
 
-static inline unsigned mv_inc_q_index(unsigned *index)
+static inline unsigned mv_inc_q_index(unsigned index)
 {
-	*index = (*index + 1) & MV_MAX_Q_DEPTH_MASK;
-	return *index;
+	return (index + 1) & MV_MAX_Q_DEPTH_MASK;
 }
 
 static inline void mv_crqb_pack_cmd(u16 *cmdw, u8 data, u8 addr, unsigned last)
@@ -1059,15 +1053,11 @@
 	u16 *cw;
 	struct ata_taskfile *tf;
 	u16 flags = 0;
+	unsigned in_index;
 
  	if (ATA_PROT_DMA != qc->tf.protocol)
 		return;
 
-	/* the req producer index should be the same as we remember it */
-	WARN_ON(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >>
-		  EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
-		pp->req_producer);
-
 	/* Fill in command request block
 	 */
 	if (!(qc->tf.flags & ATA_TFLAG_WRITE))
@@ -1075,13 +1065,17 @@
 	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
 	flags |= qc->tag << CRQB_TAG_SHIFT;
 
-	pp->crqb[pp->req_producer].sg_addr =
+	/* get current queue index from hardware */
+	in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
+			>> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+
+	pp->crqb[in_index].sg_addr =
 		cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
-	pp->crqb[pp->req_producer].sg_addr_hi =
+	pp->crqb[in_index].sg_addr_hi =
 		cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
-	pp->crqb[pp->req_producer].ctrl_flags = cpu_to_le16(flags);
+	pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
 
-	cw = &pp->crqb[pp->req_producer].ata_cmd[0];
+	cw = &pp->crqb[in_index].ata_cmd[0];
 	tf = &qc->tf;
 
 	/* Sadly, the CRQB cannot accomodate all registers--there are
@@ -1150,16 +1144,12 @@
 	struct mv_port_priv *pp = ap->private_data;
 	struct mv_crqb_iie *crqb;
 	struct ata_taskfile *tf;
+	unsigned in_index;
 	u32 flags = 0;
 
  	if (ATA_PROT_DMA != qc->tf.protocol)
 		return;
 
-	/* the req producer index should be the same as we remember it */
-	WARN_ON(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >>
-		  EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
-		pp->req_producer);
-
 	/* Fill in Gen IIE command request block
 	 */
 	if (!(qc->tf.flags & ATA_TFLAG_WRITE))
@@ -1168,7 +1158,11 @@
 	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
 	flags |= qc->tag << CRQB_TAG_SHIFT;
 
-	crqb = (struct mv_crqb_iie *) &pp->crqb[pp->req_producer];
+	/* get current queue index from hardware */
+	in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
+			>> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+
+	crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
 	crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
 	crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
 	crqb->flags = cpu_to_le32(flags);
@@ -1216,6 +1210,7 @@
 {
 	void __iomem *port_mmio = mv_ap_base(qc->ap);
 	struct mv_port_priv *pp = qc->ap->private_data;
+	unsigned in_index;
 	u32 in_ptr;
 
 	if (ATA_PROT_DMA != qc->tf.protocol) {
@@ -1227,23 +1222,20 @@
 		return ata_qc_issue_prot(qc);
 	}
 
-	in_ptr = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+	in_ptr   = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+	in_index = (in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
 
-	/* the req producer index should be the same as we remember it */
-	WARN_ON(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
-		pp->req_producer);
 	/* until we do queuing, the queue should be empty at this point */
-	WARN_ON(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
-		((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) >>
-		  EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
+	WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
+		>> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
 
-	mv_inc_q_index(&pp->req_producer);	/* now incr producer index */
+	in_index = mv_inc_q_index(in_index);	/* now incr producer index */
 
 	mv_start_dma(port_mmio, pp);
 
 	/* and write the request in pointer to kick the EDMA to life */
 	in_ptr &= EDMA_REQ_Q_BASE_LO_MASK;
-	in_ptr |= pp->req_producer << EDMA_REQ_Q_PTR_SHIFT;
+	in_ptr |= in_index << EDMA_REQ_Q_PTR_SHIFT;
 	writelfl(in_ptr, port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
 
 	return 0;
@@ -1266,28 +1258,26 @@
 {
 	void __iomem *port_mmio = mv_ap_base(ap);
 	struct mv_port_priv *pp = ap->private_data;
+	unsigned out_index;
 	u32 out_ptr;
 	u8 ata_status;
 
-	out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
-
-	/* the response consumer index should be the same as we remember it */
-	WARN_ON(((out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
-		pp->rsp_consumer);
+	out_ptr   = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
+	out_index = (out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
 
-	ata_status = pp->crpb[pp->rsp_consumer].flags >> CRPB_FLAG_STATUS_SHIFT;
+	ata_status = le16_to_cpu(pp->crpb[out_index].flags)
+					>> CRPB_FLAG_STATUS_SHIFT;
 
 	/* increment our consumer index... */
-	pp->rsp_consumer = mv_inc_q_index(&pp->rsp_consumer);
+	out_index = mv_inc_q_index(out_index);
 
 	/* and, until we do NCQ, there should only be 1 CRPB waiting */
-	WARN_ON(((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS) >>
-		  EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
-		pp->rsp_consumer);
+	WARN_ON(out_index != ((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS)
+		>> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
 
 	/* write out our inc'd consumer index so EDMA knows we're caught up */
 	out_ptr &= EDMA_RSP_Q_BASE_LO_MASK;
-	out_ptr |= pp->rsp_consumer << EDMA_RSP_Q_PTR_SHIFT;
+	out_ptr |= out_index << EDMA_RSP_Q_PTR_SHIFT;
 	writelfl(out_ptr, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
 
 	/* Return ATA status register for completed CRPB */

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

* [PATCH 6/7] sata_mv: endian fix
  2006-05-19 20:13     ` [PATCH 0/7] sata_mv: assorted fixes Mark Lord
                         ` (4 preceding siblings ...)
  2006-05-19 20:36       ` [PATCH 5/7] sata_mv: remove local copy of queue indexes Mark Lord
@ 2006-05-19 20:40       ` Mark Lord
  2006-05-19 20:41       ` [PATCH 7/7] sata_mv: version bump Mark Lord
  6 siblings, 0 replies; 38+ messages in thread
From: Mark Lord @ 2006-05-19 20:40 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linux-ide, tie-fei.zang

This fixes a byte-swap issue on PPC, found by Zang Roy-r61911
on the powerpc platform.  His original patch also had some other
platform-specific changes in #ifdef's, but I'm not sure yet how to
incorporate them.  Look for another patch for those (soon).

Signed-off-by: Mark Lord <liml@rtr.ca>

---
--- linux/drivers/scsi/sata_mv.c	2006-05-19 15:44:11.000000000 -0400
+++ linux/drivers/scsi/sata_mv.c	2006-05-19 15:58:21.000000000 -0400
@@ -1030,8 +1030,9 @@
 
 static inline void mv_crqb_pack_cmd(u16 *cmdw, u8 data, u8 addr, unsigned last)
 {
-	*cmdw = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
+	u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
 		(last ? CRQB_CMD_LAST : 0);
+	*cmdw = cpu_to_le16(tmp);
 }
 
 /**

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

* [PATCH 7/7] sata_mv: version bump
  2006-05-19 20:13     ` [PATCH 0/7] sata_mv: assorted fixes Mark Lord
                         ` (5 preceding siblings ...)
  2006-05-19 20:40       ` [PATCH 6/7] sata_mv: endian fix Mark Lord
@ 2006-05-19 20:41       ` Mark Lord
  6 siblings, 0 replies; 38+ messages in thread
From: Mark Lord @ 2006-05-19 20:41 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linux-ide

Increment the version number inside sata_mv.c.

Signed-off-by: Mark Lord <liml@rtr.ca>

---
--- linux/drivers/scsi/sata_mv.c	2006-05-19 15:44:11.000000000 -0400
+++ linux/drivers/scsi/sata_mv.c	2006-05-19 15:37:19.000000000 -0400
@@ -37,7 +37,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME	"sata_mv"
-#define DRV_VERSION	"0.6"
+#define DRV_VERSION	"0.7"
 
 enum {
 	/* BAR's are enumerated in terms of pci_resource_start() terms */

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

* Re: [PATCH 2/7] sata_mv: deal with interrupt coalescing interrupts
  2006-05-19 20:24       ` [PATCH 2/7] sata_mv: deal with interrupt coalescing interrupts Mark Lord
@ 2006-05-20  4:32         ` Jeff Garzik
  2006-05-20 13:13           ` Mark Lord
  0 siblings, 1 reply; 38+ messages in thread
From: Jeff Garzik @ 2006-05-20  4:32 UTC (permalink / raw)
  To: Mark Lord; +Cc: linux-ide

Mark Lord wrote:
> In some systems, it is possible that the BIOS may have enabled interrupt coalescing
> for the Marvell controllers which support it.  This patch adds code to detect/ack
> interrupts from the chip's coalescing (combing) logic.
> 
> Signed-off-by: Mark Lord <liml@rtr.ca>

Applied, though I would like a follow-up which simply guarantees that 
irq coalescing is off.

	Jeff




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

* Re: [PATCH 2/7] sata_mv: deal with interrupt coalescing interrupts
  2006-05-20  4:32         ` Jeff Garzik
@ 2006-05-20 13:13           ` Mark Lord
  2006-05-20 13:24             ` Jeff Garzik
  0 siblings, 1 reply; 38+ messages in thread
From: Mark Lord @ 2006-05-20 13:13 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linux-ide

Jeff Garzik wrote:
> Applied, though I would like a follow-up which simply guarantees that 
> irq coalescing is off.

Perhaps.  I'm getting pressure to do the exact opposite from users
of this chipset --> they'd like IRQ coalescing to be guaranteed to
be turned *on*.  Maybe a sysfs attr for it, with default == off ?

It'll be next week sometime, though -- long holiday weekend is here now.

Cheers

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

* Re: [PATCH 2/7] sata_mv: deal with interrupt coalescing interrupts
  2006-05-20 13:13           ` Mark Lord
@ 2006-05-20 13:24             ` Jeff Garzik
  2006-05-20 14:01               ` Mark Lord
  0 siblings, 1 reply; 38+ messages in thread
From: Jeff Garzik @ 2006-05-20 13:24 UTC (permalink / raw)
  To: Mark Lord; +Cc: linux-ide

Mark Lord wrote:
> Jeff Garzik wrote:
>> Applied, though I would like a follow-up which simply guarantees that 
>> irq coalescing is off.
> 
> Perhaps.  I'm getting pressure to do the exact opposite from users
> of this chipset --> they'd like IRQ coalescing to be guaranteed to
> be turned *on*.  Maybe a sysfs attr for it, with default == off ?

Yes, I should have been more clear.  Support is fine, as long as the 
default is off.

Unless you have a _lot_ of ports active at the same time, irq coalescing 
can increase latency.

Ideally, for this, AHCI, and any other SATA controller that does 
coalescing, we have a runtime dynamic trigger that turns on coalescing 
when interrupt traffic exceeds a runtime limit.

	Jeff




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

* Re: [PATCH 2/7] sata_mv: deal with interrupt coalescing interrupts
  2006-05-20 13:24             ` Jeff Garzik
@ 2006-05-20 14:01               ` Mark Lord
  2006-05-22  6:35                 ` Jeff Garzik
  0 siblings, 1 reply; 38+ messages in thread
From: Mark Lord @ 2006-05-20 14:01 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linux-ide

Jeff Garzik wrote:
>
> Unless you have a _lot_ of ports active at the same time, irq coalescing 
> can increase latency.

I agree, which is why I haven't actually turned it on yet.
But a runtime sysfs attr for it should allow us to benchmark
things, and see if it really helps or not under various loads.

> Ideally, for this, AHCI, and any other SATA controller that does 
> coalescing, we have a runtime dynamic trigger that turns on coalescing 
> when interrupt traffic exceeds a runtime limit.

Yeah, if coalescing turns out to be a win under hight load,
then a generic strategy like that would be a great feature.

Cheers

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

* Re: [PATCH 2/7] sata_mv: deal with interrupt coalescing interrupts
  2006-05-20 14:01               ` Mark Lord
@ 2006-05-22  6:35                 ` Jeff Garzik
  0 siblings, 0 replies; 38+ messages in thread
From: Jeff Garzik @ 2006-05-22  6:35 UTC (permalink / raw)
  To: Mark Lord; +Cc: linux-ide

Mark Lord wrote:
> Jeff Garzik wrote:
>>
>> Unless you have a _lot_ of ports active at the same time, irq 
>> coalescing can increase latency.
> 
> I agree, which is why I haven't actually turned it on yet.
> But a runtime sysfs attr for it should allow us to benchmark
> things, and see if it really helps or not under various loads.
> 
>> Ideally, for this, AHCI, and any other SATA controller that does 
>> coalescing, we have a runtime dynamic trigger that turns on coalescing 
>> when interrupt traffic exceeds a runtime limit.
> 
> Yeah, if coalescing turns out to be a win under hight load,
> then a generic strategy like that would be a great feature.

It should definitely be a win.  Every irq raised by the system, even 
with MSI, has a fixed overhead, with spinlocks being taken along the way 
or disable/enable_irq() deep in the system irq handler code.  Its a 
measurable CPU usage win reducing that overhead, if nothing else.

I've already "been there, done that" in the networking area, which 
benefits from hardware (coalescing) and software (polling) interrupt 
mitigation.  Hardware miti mitigates interrupts on a per-hardware basis, 
but doesn't have any inherent overall-system-load feedback mechanisms. 
Software miti takes into account overall system load, but can be 
somewhat dumb at times (can add overhead at low loads).  However, "high 
load" in networking easily means 10x or 100x the number of interrupts 
per second.  Networking also processes data in smaller chunks (== more 
interrupt events).  SATA is catching up though, at 3.0Gbps+ and 8-port 
cards.

	Jeff




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

* Re: [PATCH 03/13] libata-hp: implement SCSI part of hotplug
  2006-05-19 16:05   ` Jeff Garzik
@ 2006-05-23 14:52     ` Tejun Heo
  0 siblings, 0 replies; 38+ messages in thread
From: Tejun Heo @ 2006-05-23 14:52 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: mlord, albertcc, alan, axboe, forrest.zhao, linux-ide

Jeff Garzik wrote:
>> +void ata_eh_scsi_hotplug(void *data)
> 
> Would prefer ata_eh_scsi_hotplug() to be in libata-scsi.  Otherwise ACK.

Will move.

-- 
tejun


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

* Re: [PATCH 07/13] libata-hp: implement unload-unplug
  2006-05-19 16:10   ` Jeff Garzik
@ 2006-05-23 14:53     ` Tejun Heo
  0 siblings, 0 replies; 38+ messages in thread
From: Tejun Heo @ 2006-05-23 14:53 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: mlord, albertcc, alan, axboe, forrest.zhao, linux-ide

Jeff Garzik wrote:

> Seems like a nice cleanup would be to move scsi_remove_host() into 
> ata_port_detach() ?  It would be nice to remove that tidbit of SCSI host 
> management from the ->remove() hook in various drivers (mostly ahci, 
> sata_sil24, and libata-core).

Will do.

-- 
tejun


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

* [PATCH 10/13] ahci: convert to new probing mechanism and add hotplug support
  2006-05-29  6:38 [PATCHSET 03/03] add hotplug support, take 4 Tejun Heo
@ 2006-05-29  6:38 ` Tejun Heo
  2006-05-30  4:27   ` Jeff Garzik
  0 siblings, 1 reply; 38+ messages in thread
From: Tejun Heo @ 2006-05-29  6:38 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide; +Cc: Tejun Heo

Convert to new probing mechanism and add hotplug support by enabling
PORT_IRQ_PHYRDY, marking ehi for hotplug and scheduling EH on
CONNECT/PHYRDY interrupts.

Unfortunately, ahci cannot reliably wait for the first FIS34 after
hotplug.  It sometimes succeeds but times out more often than not, so
ATA_FLAG_CANT_WAIT_FIS34 is used.

This patch also fixes ahci_hardreset() such that D2H Register FIS RX
area is cleared before issuing COMRESET.  Without this,
ata_busy_sleep() after COMRESET might prematually finish if the
previous TF contains DRDY && !BSY.

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

---

 drivers/scsi/ahci.c |   47 +++++++++++++++++++++++++++--------------------
 1 files changed, 27 insertions(+), 20 deletions(-)

8cf0cb52955e53d055c16c85b648c5b9b9ef2679
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 60f455b..1fd1aa0 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -136,6 +136,7 @@ enum {
 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
 				  PORT_IRQ_IF_ERR |
 				  PORT_IRQ_CONNECT |
+				  PORT_IRQ_PHYRDY |
 				  PORT_IRQ_UNK_FIS,
 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
 				  PORT_IRQ_TF_ERR |
@@ -200,7 +201,6 @@ static void ahci_scr_write (struct ata_p
 static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
 static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
-static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes);
 static void ahci_irq_clear(struct ata_port *ap);
 static int ahci_port_start(struct ata_port *ap);
 static void ahci_port_stop(struct ata_port *ap);
@@ -241,8 +241,6 @@ static const struct ata_port_operations 
 
 	.tf_read		= ahci_tf_read,
 
-	.probe_reset		= ahci_probe_reset,
-
 	.qc_prep		= ahci_qc_prep,
 	.qc_issue		= ahci_qc_issue,
 
@@ -267,7 +265,8 @@ static const struct ata_port_info ahci_p
 	{
 		.sht		= &ahci_sht,
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
+				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+				  ATA_FLAG_SKIP_D2H_BSY,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &ahci_ops,
@@ -277,6 +276,7 @@ static const struct ata_port_info ahci_p
 		.sht		= &ahci_sht,
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+				  ATA_FLAG_SKIP_D2H_BSY |
 				  AHCI_FLAG_RESET_NEEDS_CLO,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
@@ -569,6 +569,17 @@ static int ahci_clo(struct ata_port *ap)
 	return 0;
 }
 
+static int ahci_prereset(struct ata_port *ap)
+{
+	if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
+	    (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
+		/* ATA_BUSY hasn't cleared, so send a CLO */
+		ahci_clo(ap);
+	}
+
+	return ata_std_prereset(ap);
+}
+
 static int ahci_softreset(struct ata_port *ap, unsigned int *class)
 {
 	struct ahci_port_priv *pp = ap->private_data;
@@ -678,12 +689,22 @@ static int ahci_softreset(struct ata_por
 
 static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
 {
+	struct ahci_port_priv *pp = ap->private_data;
+	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+	struct ata_taskfile tf;
 	int rc;
 
 	DPRINTK("ENTER\n");
 
 	ahci_stop_engine(ap);
+
+	/* clear D2H reception area to properly wait for FIS34 */
+	ata_tf_init(ap->device, &tf);
+	tf.command = 0xff;
+	ata_tf_to_fis(&tf, d2h_fis, 0);
+
 	rc = sata_std_hardreset(ap, class);
+
 	ahci_start_engine(ap);
 
 	if (rc == 0 && ata_port_online(ap))
@@ -714,19 +735,6 @@ static void ahci_postreset(struct ata_po
 	}
 }
 
-static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes)
-{
-	if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
-	    (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
-		/* ATA_BUSY hasn't cleared, so send a CLO */
-		ahci_clo(ap);
-	}
-
-	return ata_drive_probe_reset(ap, ata_std_probeinit,
-				     ahci_softreset, ahci_hardreset,
-				     ahci_postreset, classes);
-}
-
 static u8 ahci_check_status(struct ata_port *ap)
 {
 	void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
@@ -839,8 +847,7 @@ static void ahci_error_intr(struct ata_p
 	}
 
 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
-		err_mask |= AC_ERR_ATA_BUS;
-		action |= ATA_EH_SOFTRESET;
+		ata_ehi_hotplugged(ehi);
 		ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
 			"connection status changed" : "PHY RDY changed");
 	}
@@ -1027,7 +1034,7 @@ static void ahci_error_handler(struct at
 	}
 
 	/* perform recovery */
-	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset,
+	ata_do_eh(ap, ahci_prereset, ahci_softreset, ahci_hardreset,
 		  ahci_postreset);
 }
 
-- 
1.3.2



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

* Re: [PATCH 10/13] ahci: convert to new probing mechanism and add hotplug support
  2006-05-29  6:38 ` [PATCH 10/13] ahci: convert to new probing mechanism and add hotplug support Tejun Heo
@ 2006-05-30  4:27   ` Jeff Garzik
  0 siblings, 0 replies; 38+ messages in thread
From: Jeff Garzik @ 2006-05-30  4:27 UTC (permalink / raw)
  To: Tejun Heo; +Cc: mlord, albertcc, alan, axboe, forrest.zhao, linux-ide

Tejun Heo wrote:
> Convert to new probing mechanism and add hotplug support by enabling
> PORT_IRQ_PHYRDY, marking ehi for hotplug and scheduling EH on
> CONNECT/PHYRDY interrupts.
> 
> Unfortunately, ahci cannot reliably wait for the first FIS34 after
> hotplug.  It sometimes succeeds but times out more often than not, so
> ATA_FLAG_CANT_WAIT_FIS34 is used.
> 
> This patch also fixes ahci_hardreset() such that D2H Register FIS RX
> area is cleared before issuing COMRESET.  Without this,
> ata_busy_sleep() after COMRESET might prematually finish if the
> previous TF contains DRDY && !BSY.
> 
> Signed-off-by: Tejun Heo <htejun@gmail.com>

NAK all mention of FIS34, ACK everything else



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

* [PATCH 10/13] ahci: convert to new probing mechanism and add hotplug support
  2006-05-31 11:25 [PATCHSET 03/03] add hotplug support, take 5 Tejun Heo
@ 2006-05-31 11:25 ` Tejun Heo
  0 siblings, 0 replies; 38+ messages in thread
From: Tejun Heo @ 2006-05-31 11:25 UTC (permalink / raw)
  To: jgarzik, mlord, albertcc, alan, axboe, forrest.zhao, linux-ide; +Cc: Tejun Heo

Convert to new probing mechanism and add hotplug support by enabling
PORT_IRQ_PHYRDY, marking ehi for hotplug and scheduling EH on
CONNECT/PHYRDY interrupts.

Unfortunately, ahci cannot reliably wait for the first D2H FIS after
hotplug.  It sometimes succeeds but times out more often than not, so
ATA_FLAG_SKIP_D2H_BSY is used.

This patch also fixes ahci_hardreset() such that D2H Register FIS RX
area is cleared before issuing COMRESET.  Without this,
ata_busy_sleep() after COMRESET might prematually finish if the
previous TF contains DRDY && !BSY.

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

---

 drivers/scsi/ahci.c |   47 +++++++++++++++++++++++++++--------------------
 1 files changed, 27 insertions(+), 20 deletions(-)

4296971dd36e2c2deae0826305f591480223af88
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 60f455b..e261b37 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -136,6 +136,7 @@ enum {
 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
 				  PORT_IRQ_IF_ERR |
 				  PORT_IRQ_CONNECT |
+				  PORT_IRQ_PHYRDY |
 				  PORT_IRQ_UNK_FIS,
 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
 				  PORT_IRQ_TF_ERR |
@@ -200,7 +201,6 @@ static void ahci_scr_write (struct ata_p
 static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
 static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
-static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes);
 static void ahci_irq_clear(struct ata_port *ap);
 static int ahci_port_start(struct ata_port *ap);
 static void ahci_port_stop(struct ata_port *ap);
@@ -241,8 +241,6 @@ static const struct ata_port_operations 
 
 	.tf_read		= ahci_tf_read,
 
-	.probe_reset		= ahci_probe_reset,
-
 	.qc_prep		= ahci_qc_prep,
 	.qc_issue		= ahci_qc_issue,
 
@@ -267,7 +265,8 @@ static const struct ata_port_info ahci_p
 	{
 		.sht		= &ahci_sht,
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
+				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+				  ATA_FLAG_SKIP_D2H_BSY,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &ahci_ops,
@@ -277,6 +276,7 @@ static const struct ata_port_info ahci_p
 		.sht		= &ahci_sht,
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+				  ATA_FLAG_SKIP_D2H_BSY |
 				  AHCI_FLAG_RESET_NEEDS_CLO,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
@@ -569,6 +569,17 @@ static int ahci_clo(struct ata_port *ap)
 	return 0;
 }
 
+static int ahci_prereset(struct ata_port *ap)
+{
+	if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
+	    (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
+		/* ATA_BUSY hasn't cleared, so send a CLO */
+		ahci_clo(ap);
+	}
+
+	return ata_std_prereset(ap);
+}
+
 static int ahci_softreset(struct ata_port *ap, unsigned int *class)
 {
 	struct ahci_port_priv *pp = ap->private_data;
@@ -678,12 +689,22 @@ static int ahci_softreset(struct ata_por
 
 static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
 {
+	struct ahci_port_priv *pp = ap->private_data;
+	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+	struct ata_taskfile tf;
 	int rc;
 
 	DPRINTK("ENTER\n");
 
 	ahci_stop_engine(ap);
+
+	/* clear D2H reception area to properly wait for D2H FIS */
+	ata_tf_init(ap->device, &tf);
+	tf.command = 0xff;
+	ata_tf_to_fis(&tf, d2h_fis, 0);
+
 	rc = sata_std_hardreset(ap, class);
+
 	ahci_start_engine(ap);
 
 	if (rc == 0 && ata_port_online(ap))
@@ -714,19 +735,6 @@ static void ahci_postreset(struct ata_po
 	}
 }
 
-static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes)
-{
-	if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
-	    (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
-		/* ATA_BUSY hasn't cleared, so send a CLO */
-		ahci_clo(ap);
-	}
-
-	return ata_drive_probe_reset(ap, ata_std_probeinit,
-				     ahci_softreset, ahci_hardreset,
-				     ahci_postreset, classes);
-}
-
 static u8 ahci_check_status(struct ata_port *ap)
 {
 	void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
@@ -839,8 +847,7 @@ static void ahci_error_intr(struct ata_p
 	}
 
 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
-		err_mask |= AC_ERR_ATA_BUS;
-		action |= ATA_EH_SOFTRESET;
+		ata_ehi_hotplugged(ehi);
 		ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
 			"connection status changed" : "PHY RDY changed");
 	}
@@ -1027,7 +1034,7 @@ static void ahci_error_handler(struct at
 	}
 
 	/* perform recovery */
-	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset,
+	ata_do_eh(ap, ahci_prereset, ahci_softreset, ahci_hardreset,
 		  ahci_postreset);
 }
 
-- 
1.3.2



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

end of thread, other threads:[~2006-05-31 11:25 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-19 15:48 [PATCHSET 03/03] add hotplug support, take 3 Tejun Heo
2006-05-19 15:48 ` [PATCH 07/13] libata-hp: implement unload-unplug Tejun Heo
2006-05-19 16:10   ` Jeff Garzik
2006-05-23 14:53     ` Tejun Heo
2006-05-19 15:48 ` [PATCH 02/13] libata-hp: implement hotplug Tejun Heo
2006-05-19 16:04   ` Jeff Garzik
2006-05-19 15:48 ` [PATCH 05/13] libata-hp: hook warmplug Tejun Heo
2006-05-19 15:48 ` [PATCH 09/13] sata_sil: convert to new probing mechanism and add hotplug support Tejun Heo
2006-05-19 15:48 ` [PATCH 06/13] libata-hp: implement bootplug Tejun Heo
2006-05-19 16:09   ` Jeff Garzik
2006-05-19 15:48 ` [PATCH 01/13] libata-hp: implement ata_eh_detach_dev() Tejun Heo
2006-05-19 15:48 ` [PATCH 03/13] libata-hp: implement SCSI part of hotplug Tejun Heo
2006-05-19 16:05   ` Jeff Garzik
2006-05-23 14:52     ` Tejun Heo
2006-05-19 15:48 ` [PATCH 08/13] ata_piix: convert ata_piix to new probing mechanism Tejun Heo
2006-05-19 15:48 ` [PATCH 04/13] libata-hp: implement warmplug Tejun Heo
2006-05-19 15:48 ` [PATCH 11/13] sata_sil24: convert to new probing mechanism and add hotplug support Tejun Heo
2006-05-19 15:48 ` [PATCH 13/13] libata-hp: move ata_do_reset() to libata-eh.c Tejun Heo
2006-05-19 16:13   ` Jeff Garzik
2006-05-19 20:13     ` [PATCH 0/7] sata_mv: assorted fixes Mark Lord
2006-05-19 20:21       ` [PATCH 1/7] sata_mv: prevent unnecessary double-resets Mark Lord
2006-05-19 20:24       ` [PATCH 2/7] sata_mv: deal with interrupt coalescing interrupts Mark Lord
2006-05-20  4:32         ` Jeff Garzik
2006-05-20 13:13           ` Mark Lord
2006-05-20 13:24             ` Jeff Garzik
2006-05-20 14:01               ` Mark Lord
2006-05-22  6:35                 ` Jeff Garzik
2006-05-19 20:29       ` [PATCH 3/7] sata_mv: chip initialization fixes Mark Lord
2006-05-19 20:33       ` [PATCH 4/7] sata_mv: spurious interrupt workaround Mark Lord
2006-05-19 20:36       ` [PATCH 5/7] sata_mv: remove local copy of queue indexes Mark Lord
2006-05-19 20:40       ` [PATCH 6/7] sata_mv: endian fix Mark Lord
2006-05-19 20:41       ` [PATCH 7/7] sata_mv: version bump Mark Lord
2006-05-19 15:48 ` [PATCH 10/13] ahci: convert to new probing mechanism and add hotplug support Tejun Heo
2006-05-19 15:48 ` [PATCH 12/13] libata-hp: killl ops->probe_reset Tejun Heo
  -- strict thread matches above, loose matches on Subject: below --
2006-05-31 11:25 [PATCHSET 03/03] add hotplug support, take 5 Tejun Heo
2006-05-31 11:25 ` [PATCH 10/13] ahci: convert to new probing mechanism and add hotplug support Tejun Heo
2006-05-29  6:38 [PATCHSET 03/03] add hotplug support, take 4 Tejun Heo
2006-05-29  6:38 ` [PATCH 10/13] ahci: convert to new probing mechanism and add hotplug support Tejun Heo
2006-05-30  4:27   ` Jeff Garzik
2006-05-11 15:32 [PATCHSET 08/11] add hotplug support, take 2 Tejun Heo
2006-05-11 15:32 ` [PATCH 10/13] ahci: convert to new probing mechanism and add hotplug support 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).