aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-11-10 04:08:10 -0500
committerJeff Garzik <jeff@garzik.org>2006-12-01 22:45:55 -0500
commit55a8e2c83ce50548dfef74bb19dfe2b809cb3099 (patch)
tree1d5ed12c49a254364f9009e9cdbf4609b92f3afb
parentbff0464769f2a1bd348265de704471747378e247 (diff)
[PATCH] libata: implement presence detection via polling IDENTIFY
On some controllers (ICHs in piix mode), there is *NO* reliable way to determine device presence other than issuing IDENTIFY and see how the transaction proceeds by watching the TF status register. libata acted this way before irq-pio and phantom devices caused very little problem but now that IDENTIFY is performed using IRQ drive PIO, such phantom devices now result in multiple 30sec timeouts during boot. This patch implements ATA_FLAG_DETECT_POLLING. If a LLD sets this flag, libata core issues the initial IDENTIFY in polling mode and if the initial data transfer fails w/ HSM violation, the port is considered to be empty thus replicating the old libata and IDE behavior. Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/ata/libata-core.c19
-rw-r--r--drivers/ata/libata-eh.c23
-rw-r--r--drivers/ata/libata.h2
-rw-r--r--include/linux/libata.h3
4 files changed, 40 insertions, 7 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 090abe443820..21f8d61e5879 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1272,9 +1272,20 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
1272 1272
1273 tf.protocol = ATA_PROT_PIO; 1273 tf.protocol = ATA_PROT_PIO;
1274 1274
1275 /* presence detection using polling IDENTIFY? */
1276 if (flags & ATA_READID_DETECT)
1277 tf.flags |= ATA_TFLAG_POLLING;
1278
1275 err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, 1279 err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
1276 id, sizeof(id[0]) * ATA_ID_WORDS); 1280 id, sizeof(id[0]) * ATA_ID_WORDS);
1277 if (err_mask) { 1281 if (err_mask) {
1282 if ((flags & ATA_READID_DETECT) &&
1283 (err_mask & AC_ERR_NODEV_HINT)) {
1284 DPRINTK("ata%u.%d: NODEV after polling detection\n",
1285 ap->id, dev->devno);
1286 return -ENOENT;
1287 }
1288
1278 rc = -EIO; 1289 rc = -EIO;
1279 reason = "I/O error"; 1290 reason = "I/O error";
1280 goto err_out; 1291 goto err_out;
@@ -4285,8 +4296,12 @@ fsm_start:
4285 /* device stops HSM for abort/error */ 4296 /* device stops HSM for abort/error */
4286 qc->err_mask |= AC_ERR_DEV; 4297 qc->err_mask |= AC_ERR_DEV;
4287 else 4298 else
4288 /* HSM violation. Let EH handle this */ 4299 /* HSM violation. Let EH handle this.
4289 qc->err_mask |= AC_ERR_HSM; 4300 * Phantom devices also trigger this
4301 * condition. Mark hint.
4302 */
4303 qc->err_mask |= AC_ERR_HSM |
4304 AC_ERR_NODEV_HINT;
4290 4305
4291 ap->hsm_task_state = HSM_ST_ERR; 4306 ap->hsm_task_state = HSM_ST_ERR;
4292 goto fsm_start; 4307 goto fsm_start;
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 755fc68b5374..e69f3df2ea39 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1667,12 +1667,23 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
1667 ata_class_enabled(ehc->classes[dev->devno])) { 1667 ata_class_enabled(ehc->classes[dev->devno])) {
1668 dev->class = ehc->classes[dev->devno]; 1668 dev->class = ehc->classes[dev->devno];
1669 1669
1670 if (ap->flags & ATA_FLAG_DETECT_POLLING)
1671 readid_flags |= ATA_READID_DETECT;
1672
1670 rc = ata_dev_read_id(dev, &dev->class, readid_flags, 1673 rc = ata_dev_read_id(dev, &dev->class, readid_flags,
1671 dev->id); 1674 dev->id);
1672 if (rc == 0) { 1675 if (rc == 0) {
1673 ehc->i.flags |= ATA_EHI_PRINTINFO; 1676 ehc->i.flags |= ATA_EHI_PRINTINFO;
1674 rc = ata_dev_configure(dev); 1677 rc = ata_dev_configure(dev);
1675 ehc->i.flags &= ~ATA_EHI_PRINTINFO; 1678 ehc->i.flags &= ~ATA_EHI_PRINTINFO;
1679 } else if (rc == -ENOENT) {
1680 /* IDENTIFY was issued to non-existent
1681 * device. No need to reset. Just
1682 * thaw and kill the device.
1683 */
1684 ata_eh_thaw_port(ap);
1685 dev->class = ATA_DEV_UNKNOWN;
1686 rc = 0;
1676 } 1687 }
1677 1688
1678 if (rc) { 1689 if (rc) {
@@ -1680,12 +1691,14 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
1680 break; 1691 break;
1681 } 1692 }
1682 1693
1683 spin_lock_irqsave(ap->lock, flags); 1694 if (ata_dev_enabled(dev)) {
1684 ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; 1695 spin_lock_irqsave(ap->lock, flags);
1685 spin_unlock_irqrestore(ap->lock, flags); 1696 ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
1697 spin_unlock_irqrestore(ap->lock, flags);
1686 1698
1687 /* new device discovered, configure transfer mode */ 1699 /* new device discovered, configure xfermode */
1688 ehc->i.flags |= ATA_EHI_SETMODE; 1700 ehc->i.flags |= ATA_EHI_SETMODE;
1701 }
1689 } 1702 }
1690 } 1703 }
1691 1704
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index bb98390aa01a..be2ac39f013b 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -42,6 +42,8 @@ struct ata_scsi_args {
42enum { 42enum {
43 /* flags for ata_dev_read_id() */ 43 /* flags for ata_dev_read_id() */
44 ATA_READID_POSTRESET = (1 << 0), /* reading ID after reset */ 44 ATA_READID_POSTRESET = (1 << 0), /* reading ID after reset */
45 ATA_READID_DETECT = (1 << 1), /* perform presence detection
46 * using polling IDENTIFY */
45}; 47};
46 48
47extern struct workqueue_struct *ata_aux_wq; 49extern struct workqueue_struct *ata_aux_wq;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 36e233cc3886..9080789913f7 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -176,6 +176,8 @@ enum {
176 ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H 176 ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H
177 * Register FIS clearing BSY */ 177 * Register FIS clearing BSY */
178 ATA_FLAG_DEBUGMSG = (1 << 13), 178 ATA_FLAG_DEBUGMSG = (1 << 13),
179 ATA_FLAG_DETECT_POLLING = (1 << 14), /* detect device presence by
180 * polling IDENTIFY */
179 181
180 /* The following flag belongs to ap->pflags but is kept in 182 /* The following flag belongs to ap->pflags but is kept in
181 * ap->flags because it's referenced in many LLDs and will be 183 * ap->flags because it's referenced in many LLDs and will be
@@ -335,6 +337,7 @@ enum ata_completion_errors {
335 AC_ERR_SYSTEM = (1 << 6), /* system error */ 337 AC_ERR_SYSTEM = (1 << 6), /* system error */
336 AC_ERR_INVALID = (1 << 7), /* invalid argument */ 338 AC_ERR_INVALID = (1 << 7), /* invalid argument */
337 AC_ERR_OTHER = (1 << 8), /* unknown */ 339 AC_ERR_OTHER = (1 << 8), /* unknown */
340 AC_ERR_NODEV_HINT = (1 << 9), /* polling device detection hint */
338}; 341};
339 342
340/* forward declarations */ 343/* forward declarations */