Add support for ATA Power Management.

This commit is contained in:
Alexander Motin 2009-11-09 11:39:51 +00:00
parent d28e9c146a
commit 50c9a27603
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=199079
2 changed files with 134 additions and 3 deletions

View File

@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd September 4, 2009
.Dd November 9, 2009
.Dt CAMCONTROL 8
.Os
.Sh NAME
@ -165,6 +165,20 @@
.Op Fl w
.Op Fl y
.Nm
.Ic idle
.Op device id
.Op generic args
.Op Fl t Ar time
.Nm
.Ic standby
.Op device id
.Op generic args
.Op Fl t Ar time
.Nm
.Ic sleep
.Op device id
.Op generic args
.Nm
.Ic help
.Sh DESCRIPTION
The
@ -821,6 +835,15 @@ The user
will not be asked about the timeout if a timeout is specified on the
command line.
.El
.It Ic idle
Put ATA device into IDLE state. Optional parameter specifies automatic
idle timer value in seconds.
.It Ic standby
Put ATA device into STANDBY state. Optional parameter specifies automatic
standby timer value in seconds.
.It Ic sleep
Put ATA device into SLEEP state. Note that the only way get device out of
this state may be reset.
.It Ic help
Print out verbose usage information.
.El

View File

@ -74,7 +74,10 @@ typedef enum {
CAM_CMD_DETACH = 0x00000010,
CAM_CMD_REPORTLUNS = 0x00000011,
CAM_CMD_READCAP = 0x00000012,
CAM_CMD_IDENTIFY = 0x00000013
CAM_CMD_IDENTIFY = 0x00000013,
CAM_CMD_IDLE = 0x00000014,
CAM_CMD_STANDBY = 0x00000015,
CAM_CMD_SLEEP = 0x00000016
} cam_cmdmask;
typedef enum {
@ -154,6 +157,9 @@ struct camcontrol_opts option_table[] = {
{"rate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts},
{"debug", CAM_CMD_DEBUG, CAM_ARG_NONE, "IPTSXc"},
{"format", CAM_CMD_FORMAT, CAM_ARG_NONE, "qrwy"},
{"idle", CAM_CMD_IDLE, CAM_ARG_NONE, "t:"},
{"standby", CAM_CMD_STANDBY, CAM_ARG_NONE, "t:"},
{"sleep", CAM_CMD_SLEEP, CAM_ARG_NONE, ""},
#endif /* MINIMALISTIC */
{"help", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
{"-?", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
@ -217,6 +223,8 @@ static int scsireportluns(struct cam_device *device, int argc, char **argv,
char *combinedopt, int retry_count, int timeout);
static int scsireadcapacity(struct cam_device *device, int argc, char **argv,
char *combinedopt, int retry_count, int timeout);
static int atapm(struct cam_device *device, int argc, char **argv,
char *combinedopt, int retry_count, int timeout);
#endif /* MINIMALISTIC */
camcontrol_optret
@ -4128,6 +4136,91 @@ scsireadcapacity(struct cam_device *device, int argc, char **argv,
return (retval);
}
static int
atapm(struct cam_device *device, int argc, char **argv,
char *combinedopt, int retry_count, int timeout)
{
union ccb *ccb;
int retval = 0;
int t = -1;
char c;
u_char cmd, sc;
ccb = cam_getccb(device);
if (ccb == NULL) {
warnx("%s: error allocating ccb", __func__);
return (1);
}
while ((c = getopt(argc, argv, combinedopt)) != -1) {
switch (c) {
case 't':
t = atoi(optarg);
break;
default:
break;
}
}
if (strcmp(argv[1], "idle") == 0) {
if (t == -1)
cmd = ATA_IDLE_IMMEDIATE;
else
cmd = ATA_IDLE_CMD;
} else if (strcmp(argv[1], "standby") == 0) {
if (t == -1)
cmd = ATA_STANDBY_IMMEDIATE;
else
cmd = ATA_STANDBY_CMD;
} else {
cmd = ATA_SLEEP;
t = -1;
}
if (t < 0)
sc = 0;
else if (t <= (240 * 5))
sc = t / 5;
else if (t <= (11 * 30 * 60))
sc = t / (30 * 60) + 241;
else
sc = 253;
cam_fill_ataio(&ccb->ataio,
retry_count,
NULL,
/*flags*/CAM_DIR_NONE,
MSG_SIMPLE_Q_TAG,
/*data_ptr*/NULL,
/*dxfer_len*/0,
timeout ? timeout : 30 * 1000);
ata_28bit_cmd(&ccb->ataio, cmd, 0, 0, sc);
/* Disable freezing the device queue */
ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
if (arglist & CAM_ARG_ERR_RECOVER)
ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
if (cam_send_ccb(device, ccb) < 0) {
warn("error sending command");
if (arglist & CAM_ARG_VERBOSE)
cam_error_print(device, ccb, CAM_ESF_ALL,
CAM_EPF_ALL, stderr);
retval = 1;
goto bailout;
}
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
retval = 1;
goto bailout;
}
bailout:
cam_freeccb(ccb);
return (retval);
}
#endif /* MINIMALISTIC */
void
@ -4166,6 +4259,9 @@ usage(int verbose)
" [-R syncrate][-v][-T <enable|disable>]\n"
" [-U][-W bus_width]\n"
" camcontrol format [dev_id][generic args][-q][-r][-w][-y]\n"
" camcontrol idle [dev_id][generic args][-t time]\n"
" camcontrol standby [dev_id][generic args][-t time]\n"
" camcontrol sleep [dev_id][generic args]\n"
#endif /* MINIMALISTIC */
" camcontrol help\n");
if (!verbose)
@ -4193,6 +4289,9 @@ usage(int verbose)
"tags report or set the number of transaction slots for a device\n"
"negotiate report or set device negotiation parameters\n"
"format send the SCSI FORMAT UNIT command to the named device\n"
"idle send the ATA IDLE command to the named device\n"
"standby send the ATA STANDBY command to the named device\n"
"sleep send the ATA SLEEP command to the named device\n"
"help this message\n"
"Device Identifiers:\n"
"bus:target specify the bus and target, lun defaults to 0\n"
@ -4259,7 +4358,9 @@ usage(int verbose)
"-q be quiet, don't print status messages\n"
"-r run in report only mode\n"
"-w don't send immediate format command\n"
"-y don't ask any questions\n");
"-y don't ask any questions\n"
"idle/standby arguments:\n"
"-t <arg> number of seconds before respective state.\n");
#endif /* MINIMALISTIC */
}
@ -4555,6 +4656,13 @@ main(int argc, char **argv)
combinedopt, retry_count,
timeout);
break;
case CAM_CMD_IDLE:
case CAM_CMD_STANDBY:
case CAM_CMD_SLEEP:
error = atapm(cam_dev, argc, argv,
combinedopt, retry_count,
timeout);
break;
#endif /* MINIMALISTIC */
case CAM_CMD_USAGE:
usage(1);