Re: [linux-pm] [RFC] Deferred disk spinup during system resume

Previous thread: [Bug 21172] OOPS in disk_replace_part_tbl. by bugzilla-daemon on Tuesday, December 28, 2010 - 3:09 pm. (1 message)

Next thread: iscsi changes for 2.6.38 by michaelc on Friday, December 31, 2010 - 1:22 am. (6 messages)
From: Maksim Rayskiy
Date: Thursday, December 30, 2010 - 12:40 pm

Hello,

When resuming from system suspend, scsi disks are being spun up which
takes quite a lot of time (5+ seconds in my case). The spinup is done
synchronously, so this time adds up to overall system resume time.
Ours is an embedded platform and we are using flash-based rootfs, so
there is no immediate need in harddrive after resume. What is much
more important for us is to minimize time-to-full-power. To speed up
resume, we would like to have an option to defer the spinup or run it
in parallel with system resume. I could not find any existing
mechanism to do the trick, but I might have missed something.

Can anybody comment on this?

Thanks,
Maksim.
--

From: Rafael J. Wysocki
Date: Thursday, December 30, 2010 - 3:46 pm

Do you use asynchronous suspend/resume?

Rafael
--

From: Maksim Rayskiy
Date: Thursday, December 30, 2010 - 5:49 pm

Yes, asynchronous suspend/resume is enabled - it saves about 0.5
second in my case. But resume blocks anyway because disk driver is
waiting on sd_resume() to complete.

I am wondering if we could let the resume proceed while spinup is
going on, just mark the scsi device as quiescent to block any data
transfers.

--

From: Tejun Heo
Date: Friday, December 31, 2010 - 4:27 am

Yeah, it was asynchronous for a while when suspend/resume were
implemented in libata proper.  It's a bit trickier to do that with sd
doing the higher level part.  Hmmm... most SATA disks spin up
automatically anyway so disabling START_STOP from sd should do the
trick.  Does the following achieve async resume?

 echo 0 > /sys/block/sdX/device/scsi_disk/h:c:i:l/manage_start_stop

The problem is that the above would also prevent the kernel from
issuing STANDBY_NOW on suspend or power down.  Maybe we should just
make start_stop_xlat schedule async EH action instead.

Thanks.

-- 
tejun
--

From: Tejun Heo
Date: Friday, December 31, 2010 - 4:45 am

So, something like the following.  It's completely untested.  Proceed
with caution.

diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 17a6378..d8d2aa8 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -3252,6 +3252,48 @@ static int ata_eh_maybe_retry_flush(struct ata_device *dev)
 	return rc;
 }
 
+static int ata_eh_maybe_verify(struct ata_device *dev)
+{
+	struct ata_link *link = dev->link;
+	struct ata_taskfile tf;
+	unsigned int err_mask;
+	int rc = 0;
+
+	ata_eh_about_to_do(link, dev, ATA_EH_VERIFY);
+
+	ata_tf_init(dev, &tf);
+
+	if (dev->flags & ATA_DFLAG_LBA) {
+		tf.flags |= ATA_TFLAG_LBA;
+
+		tf.lbah = 0x0;
+		tf.lbam = 0x0;
+		tf.lbal = 0x0;
+		tf.device |= ATA_LBA;
+	} else {
+		/* CHS */
+		tf.lbal = 0x1; /* sect */
+		tf.lbam = 0x0; /* cyl low */
+		tf.lbah = 0x0; /* cyl high */
+	}
+
+	tf.command = ATA_CMD_VERIFY;	/* READ VERIFY */
+	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE;
+	tf.protocol = ATA_PROT_NODATA;
+
+	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+	if (err_mask) {
+		ata_dev_printk(dev, KERN_WARNING,
+			       "READ_VERIFY failed Emask 0x%x\n", err_mask);
+		rc = -EIO;
+	}
+
+	/* don't retry VERIFY */
+	ata_eh_done(link, dev, ATA_EH_VERIFY);
+
+	return rc;
+}
+
 /**
  *	ata_eh_set_lpm - configure SATA interface power management
  *	@link: link to configure power management
@@ -3749,6 +3791,9 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
 			rc = ata_eh_maybe_retry_flush(dev);
 			if (rc)
 				goto rest_fail;
+			rc = ata_eh_maybe_verify(dev);
+			if (rc)
+				goto rest_fail;
 		}
 
 	config_lpm:
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 66aa4be..ae8d9ca 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1276,6 +1276,7 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth,
  */
 static unsigned int ...
Previous thread: [Bug 21172] OOPS in disk_replace_part_tbl. by bugzilla-daemon on Tuesday, December 28, 2010 - 3:09 pm. (1 message)

Next thread: iscsi changes for 2.6.38 by michaelc on Friday, December 31, 2010 - 1:22 am. (6 messages)