ata explicit idle/standby
Michael Weiser
michael at weiser.dinsnail.net
Sat Jun 18 16:20:52 GMT 2005
Hi,
I've done a small patch to the -CURRENT atacontrol and ata driver to
allow explicit switch of drives to idle or standby mode and query the
current mode. I use it to spin down disks needed only very inregularly.
If extended by a means to set the idle timeout this might be
particularly useful to notebook users as well.
Or have I actually missed the some already present functionality to
achieve the same?
--
Cheers,
Micha
-------------- next part --------------
--- sys/dev/ata/ata-all.c.orig Tue Jun 7 17:33:23 2005
+++ sys/dev/ata/ata-all.c Sat Jun 18 17:12:48 2005
@@ -493,6 +493,38 @@
case IOCATAGMODE:
*mode = atadev->mode;
return 0;
+
+ case IOCATASTANDBY:
+ if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE)
+ ata_controlcmd(dev, ATA_FLUSHCACHE, 0, 0, 0);
+
+ ata_controlcmd(dev, ATA_STANDBY_IMMEDIATE, 0, 0, 0);
+ return 0;
+
+ case IOCATAIDLE:
+ if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE)
+ ata_controlcmd(dev, ATA_FLUSHCACHE, 0, 0, 0);
+
+ ata_controlcmd(dev, ATA_IDLE_IMMEDIATE, 0, 0, 0);
+ return 0;
+
+ case IOCATACHECKPWRMODE:
+ if (!(request = ata_alloc_request()))
+ return ENOMEM;
+
+ request->dev = dev;
+ request->u.ata.command = ATA_CHECK_PWR_MODE;
+ request->u.ata.lba = 0;
+ request->u.ata.count = 0;
+ request->u.ata.feature = 0;
+ request->flags = ATA_R_CONTROL;
+ request->timeout = 1;
+ request->retries = 0;
+ ata_queue_request(request);
+ *mode = request->u.ata.count;
+ ata_free_request(request);
+ return 0;
+
default:
return ENOTTY;
}
--- sbin/atacontrol/atacontrol.c.orig Tue Jun 7 17:27:41 2005
+++ sbin/atacontrol/atacontrol.c Sat Jun 18 17:10:47 2005
@@ -109,6 +109,9 @@
" atacontrol status array\n"
" atacontrol mode device [mode]\n"
" atacontrol cap device\n"
+ " atacontrol pwrstatus device\n"
+ " atacontrol standby device\n"
+ " atacontrol idle device\n"
);
exit(EX_USAGE);
}
@@ -337,6 +340,77 @@
if ((fd = open(device, O_RDONLY)) < 0)
err(1, "device not found");
ata_cap_print(fd);
+ exit(EX_OK);
+ }
+ if (!strcmp(argv[1], "idle") && argc == 3) {
+ int disk;
+ char device[64];
+
+ if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
+ sscanf(argv[2], "acd%d", &disk) == 1 ||
+ sscanf(argv[2], "afd%d", &disk) == 1 ||
+ sscanf(argv[2], "ast%d", &disk) == 1)) {
+ fprintf(stderr, "atacontrol: Invalid device %s\n",
+ argv[2]);
+ exit(EX_USAGE);
+ }
+ sprintf(device, "/dev/%s", argv[2]);
+ if ((fd = open(device, O_RDONLY)) < 0)
+ err(1, "device not found");
+ if (ioctl(fd, IOCATAIDLE, &disk) < 0)
+ err(1, "ioctl(ATAIDLE)");
+ exit(EX_OK);
+ }
+ if (!strcmp(argv[1], "standby") && argc == 3) {
+ int disk;
+ char device[64];
+
+ if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
+ sscanf(argv[2], "acd%d", &disk) == 1 ||
+ sscanf(argv[2], "afd%d", &disk) == 1 ||
+ sscanf(argv[2], "ast%d", &disk) == 1)) {
+ fprintf(stderr, "atacontrol: Invalid device %s\n",
+ argv[2]);
+ exit(EX_USAGE);
+ }
+ sprintf(device, "/dev/%s", argv[2]);
+ if ((fd = open(device, O_RDONLY)) < 0)
+ err(1, "device not found");
+ if (ioctl(fd, IOCATASTANDBY, &disk) < 0)
+ err(1, "ioctl(ATASTANDBY)");
+ exit(EX_OK);
+ }
+ if (!strcmp(argv[1], "pwrstatus") && argc == 3) {
+ int disk;
+ char device[64];
+
+ if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
+ sscanf(argv[2], "acd%d", &disk) == 1 ||
+ sscanf(argv[2], "afd%d", &disk) == 1 ||
+ sscanf(argv[2], "ast%d", &disk) == 1)) {
+ fprintf(stderr, "atacontrol: Invalid device %s\n",
+ argv[2]);
+ exit(EX_USAGE);
+ }
+ sprintf(device, "/dev/%s", argv[2]);
+ if ((fd = open(device, O_RDONLY)) < 0)
+ err(1, "device not found");
+ if (ioctl(fd, IOCATACHECKPWRMODE, &disk) < 0)
+ err(1, "ioctl(ATACHECKPWRMODE)");
+ switch (disk) {
+ case 0x00:
+ printf("device is in standby mode\n");
+ break;
+ case 0x80:
+ printf("device is in idle mode\n");
+ break;
+ case 0xff:
+ printf("device is in active or idle mode\n");
+ break;
+ default:
+ printf("unknown mode\n");
+ break;
+ }
exit(EX_OK);
}
--- sys/sys/ata.h.orig Tue Jun 7 17:42:52 2005
+++ sys/sys/ata.h Sat Jun 18 18:01:30 2005
@@ -252,6 +252,7 @@
#define ATA_STANDBY_CMD 0xe2 /* standby */
#define ATA_IDLE_CMD 0xe3 /* idle */
#define ATA_READ_BUFFER 0xe4 /* read buffer */
+#define ATA_CHECK_PWR_MODE 0xe5 /* check power mode */
#define ATA_SLEEP 0xe6 /* sleep */
#define ATA_FLUSHCACHE 0xe7 /* flush cache to disk */
#define ATA_FLUSHCACHE48 0xea /* flush cache to disk */
@@ -372,6 +373,9 @@
#define IOCATAGPARM _IOR('a', 101, struct ata_params)
#define IOCATAGMODE _IOR('a', 102, int)
#define IOCATASMODE _IOW('a', 103, int)
+#define IOCATAIDLE _IOW('a', 131, int)
+#define IOCATASTANDBY _IOW('a', 132, int)
+#define IOCATACHECKPWRMODE _IOR('a', 133, int)
struct ata_ioc_raid_config {
More information about the freebsd-current
mailing list