bin/88634: Add idle and standby commands to atacontrol

Jean-Yves Lefort jylefort at FreeBSD.org
Mon Nov 7 17:40:12 PST 2005


>Number:         88634
>Category:       bin
>Synopsis:       Add idle and standby commands to atacontrol
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue Nov 08 01:40:10 GMT 2005
>Closed-Date:
>Last-Modified:
>Originator:     Jean-Yves Lefort
>Release:        FreeBSD 6.0-RELEASE i386
>Organization:
>Environment:
System: FreeBSD jsite.lefort.net 6.0-RELEASE FreeBSD 6.0-RELEASE #0: Mon Nov 7 19:32:08 CET 2005 jylefort at jsite.lefort.net:/usr/obj/usr/src/sys/JSITE i386
>Description:
Inspired by sysutils/ataidle. Timer calculation taken from NetBSD's atactl.
>How-To-Repeat:
>Fix:
--- atacontrol.8.orig	Fri Aug 19 17:54:42 2005
+++ atacontrol.8	Tue Nov  8 01:51:32 2005
@@ -64,6 +64,12 @@
 .Ic mode
 .Ar device
 .Nm
+.Ic idle
+.Ar device Oo Ar seconds Oc
+.Nm
+.Ic standby
+.Ar device Oo Ar seconds Oc
+.Nm
 .Ic info
 .Ar channel
 .Nm
@@ -187,6 +193,20 @@
 (alias
 .Cm UDMA133 ) .
 The device name and manufacture/version strings are shown.
+.It Ic idle
+Place
+.Ar device
+into idle mode. Additionally, if
+.Ar seconds
+are specified, set the idle timer to that number of seconds. A value of
+0 will disable the idle timer.
+.It Ic standby
+Place
+.Ar device
+into standby mode. Additionally, if
+.Ar seconds
+are specified, set the standby timer to that number of seconds. A value of
+0 will disable the standby timer.
 .It Ic cap
 Show detailed info about the device on
 .Ar device .
--- atacontrol.c.orig	Sun Aug  7 13:16:58 2005
+++ atacontrol.c	Tue Nov  8 02:02:51 2005
@@ -37,6 +37,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <limits.h>
 #include <string.h>
 #include <sysexits.h>
 
@@ -48,6 +49,8 @@
 void cap_print(struct ata_params *parm);
 int ata_cap_print(int fd);
 int info_print(int fd, int channel, int prchan);
+int open_device(const char *name);
+void set_power(int fd, const char *seconds, u_int8_t immediate_command, u_int8_t set_command);
 
 const char *
 mode2str(int mode)
@@ -108,6 +111,8 @@
 		"        atacontrol rebuild array\n"
 		"        atacontrol status array\n"
 		"        atacontrol mode device [mode]\n"
+		"        atacontrol idle device [seconds]\n"
+		"        atacontrol standby device [seconds]\n"
 		"        atacontrol cap device\n"
 	);
 	exit(EX_USAGE);
@@ -287,6 +292,68 @@
 }
 
 int
+open_device(const char *name)
+{
+	int disk;
+	int fd;
+	char device[64];
+
+	if (!(sscanf(name, "ad%d", &disk) == 1 ||
+	      sscanf(name, "acd%d", &disk) == 1 ||
+	      sscanf(name, "afd%d", &disk) == 1 ||
+	      sscanf(name, "ast%d", &disk) == 1)) {
+		fprintf(stderr, "atacontrol: Invalid device %s\n",
+			name);
+		exit(EX_USAGE);
+	}
+
+	sprintf(device, "/dev/%s", name);
+	if ((fd = open(device, O_RDONLY)) < 0)
+		err(1, "device not found");
+
+	return fd;
+}
+
+void
+set_power(int fd, const char *seconds, u_int8_t immediate_command, u_int8_t set_command)
+{
+	struct ata_ioc_request request;
+
+	memset(&request, 0, sizeof(request));
+	request.flags = ATA_CMD_CONTROL;
+	request.timeout = 1000;
+	if (seconds) {
+		unsigned long idle;
+		char *end;
+
+		idle = strtoul(seconds, &end, 0);
+
+		if (*end != '\0') {
+			fprintf(stderr, "atacontrol: Invalid idle time %s\n", seconds);
+                        exit(EX_USAGE);
+		}
+		if (idle > 19800) {
+			fprintf(stderr, "atacontrol: Idle time has a maximum value of 5.5 hours\n");
+                        exit(EX_USAGE);
+		}
+		if (idle != 0 && idle < 5) {
+			fprintf(stderr, "atacontrol: Idle time must be at least 5 seconds\n");
+                        exit(EX_USAGE);
+		}
+
+		request.u.ata.command = set_command;
+		if (idle <= 240 * 5)
+			request.u.ata.count = idle / 5;
+		else
+			request.u.ata.count = idle / (30 * 60) + 240;
+	} else
+		request.u.ata.command = immediate_command;
+
+	if (ioctl(fd, IOCATAREQUEST, &request) < 0)
+		err(1, "ioctl(IOCATAREQUEST)");
+}
+
+int
 main(int argc, char **argv)
 {
 	int fd;
@@ -295,20 +362,8 @@
 		usage();
 
 	if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 4)) {
-		int disk, mode;
-		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");
+		int mode;
+		fd = open_device(argv[2]);
 		if (argc == 4) {
 			mode = str2mode(argv[3]);
 			if (ioctl(fd, IOCATASMODE, &mode) < 0)
@@ -321,21 +376,20 @@
 		}
 		exit(EX_OK);
 	}
+	if (!strcmp(argv[1], "idle") && (argc == 3 || argc == 4)) {
+		fd = open_device(argv[2]);
+		set_power(fd, argc == 4 ? argv[3] : NULL,
+			  ATA_IDLE_IMMEDIATE, ATA_IDLE_CMD);
+		exit(EX_OK);
+	}
+	if (!strcmp(argv[1], "standby") && (argc == 3 || argc == 4)) {
+		fd = open_device(argv[2]);
+		set_power(fd, argc == 4 ? argv[3] : NULL,
+			  ATA_STANDBY_IMMEDIATE, ATA_STANDBY_CMD);
+		exit(EX_OK);
+	}
 	if (!strcmp(argv[1], "cap") && 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");
+		fd = open_device(argv[2]);
 		ata_cap_print(fd);
 		exit(EX_OK);
 	}
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list