2
* Copyright (c) 2006 Douglas Gilbert.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
* 3. The name of the author may not be used to endorse or promote products
14
* derived from this software without specific prior written permission.
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36
#include <sys/ioctl.h>
37
#include <sys/types.h>
40
#include "sg_io_linux.h"
42
/* This program performs a ATA PASS THROUGH (16) SCSI command in order
43
to perform an ATA CHECK POWER MODE command. See http://www.t10.org
44
SAT draft at time of writing: sat-r08.pdf
46
Invocation: sg_sat_chk_power [-v] [-V] <device>
50
#define SAT_ATA_PASS_THROUGH16 0x85
51
#define SAT_ATA_PASS_THROUGH16_LEN 16
52
#define SAT_STATUS_RETURN_DESC 9 /* ATA status return (sense) descriptor */
54
#define ATA_CHECK_POWER_MODE 0xe5
58
static char * version_str = "1.02 20060629";
60
int main(int argc, char * argv[])
63
unsigned char aptCmdBlk[SAT_ATA_PASS_THROUGH16_LEN] =
64
{SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0,
65
0, 0, 0, 0, 0, 0, 0, 0};
69
unsigned char sense_buffer[64];
72
int chk_cond = 1; /* set to 1 to read register(s) back */
73
int protocol = 3; /* non-dat data-in */
74
int t_dir = 1; /* 0 -> to device, 1 -> from device */
75
int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */
76
int t_length = 0; /* 0 -> no data transferred, 2 -> sector count */
77
const unsigned char * ucp = NULL;
79
for (k = 1; k < argc; ++k) {
80
if (0 == strcmp(argv[k], "-v"))
82
else if (0 == strcmp(argv[k], "-vv"))
84
else if (0 == strcmp(argv[k], "-V")) {
85
fprintf(stderr, "version: %s\n", version_str);
87
} else if (*argv[k] == '-') {
88
printf("Unrecognized switch: %s\n", argv[k]);
92
else if (0 == file_name)
95
printf("too many arguments\n");
100
if (0 == file_name) {
101
printf("Usage: 'sg_sat_chk_power [-v] [-V] <device>'\n");
105
if ((sg_fd = open(file_name, O_RDWR)) < 0) {
106
snprintf(ebuff, EBUFF_SZ,
107
"sg_sat_chk_power: error opening file: %s", file_name);
112
/* Prepare ATA PASS THROUGH COMMAND (16) command */
113
aptCmdBlk[14] = ATA_CHECK_POWER_MODE;
114
aptCmdBlk[1] = (protocol << 1) | extend;
115
aptCmdBlk[2] = (chk_cond << 5) | (t_dir << 3) |
116
(byte_block << 2) | t_length;
118
fprintf(stderr, " ata pass through(16) cdb: ");
119
for (k = 0; k < SAT_ATA_PASS_THROUGH16_LEN; ++k)
120
fprintf(stderr, "%02x ", aptCmdBlk[k]);
121
fprintf(stderr, "\n");
124
memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
125
io_hdr.interface_id = 'S';
126
io_hdr.cmd_len = sizeof(aptCmdBlk);
127
/* io_hdr.iovec_count = 0; */ /* memset takes care of this */
128
io_hdr.mx_sb_len = sizeof(sense_buffer);
129
io_hdr.dxfer_direction = SG_DXFER_NONE;
130
io_hdr.dxfer_len = 0;
131
io_hdr.dxferp = NULL;
132
io_hdr.cmdp = aptCmdBlk;
133
io_hdr.sbp = sense_buffer;
134
io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */
135
/* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */
136
/* io_hdr.pack_id = 0; */
137
/* io_hdr.usr_ptr = NULL; */
139
if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
140
perror("sg_sat_chk_power: SG_IO ioctl error");
145
/* error processing: N.B. expect check condition, no sense ... !! */
146
switch (sg_err_category3(&io_hdr)) {
147
case SG_LIB_CAT_CLEAN:
149
case SG_LIB_CAT_RECOVERED:
150
case SG_LIB_CAT_NO_SENSE:
151
/* XXX: Until the spec decides which one to go with. 20060607 */
152
ucp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer),
153
SAT_STATUS_RETURN_DESC);
155
sg_chk_n_print3("ATA_16 command error", &io_hdr, 1);
157
sg_chk_n_print3("status return descriptor, as expected",
161
printf("error in returned FIS: aborted command\n");
163
printf("error=0x%x, status=0x%x\n", ucp[3], ucp[13]);
167
fprintf(stderr, "unexpected SCSI sense category\n");
168
ucp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer),
169
SAT_STATUS_RETURN_DESC);
171
sg_chk_n_print3("ATA_16 command error", &io_hdr, 1);
173
sg_chk_n_print3("status return descriptor, as expected",
177
printf("error in returned FIS: aborted command\n");
179
printf("error=0x%x, status=0x%x\n", ucp[3], ucp[13]);
185
switch (ucp[5]) { /* sector_count (7:0) */
187
printf("In active mode or idle mode\n");
190
printf("In idle mode\n");
193
printf("In NV power mode and spindle is spun or spinning up\n");
196
printf("In NV power mode and spindle is spun or spinning down\n");
199
printf("In standby mode\n");
202
printf("unknown power mode (sector count) value=0x%x\n", ucp[5]);
206
fprintf(stderr, "Expecting a special error return and didn't "