2 * ata_id - reads product/serial number from ATA drives
4 * Copyright (C) 2005-2008 Kay Sievers <kay@vrfy.org>
5 * Copyright (C) 2009 Lennart Poettering <lennart@poettering.net>
6 * Copyright (C) 2009-2010 David Zeuthen <zeuthen@gmail.com>
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 #include <scsi/scsi.h>
33 #include <scsi/scsi_ioctl.h>
34 #include <sys/ioctl.h>
35 #include <sys/types.h>
37 #include <linux/types.h>
38 #include <linux/hdreg.h>
40 #include <linux/cdrom.h>
41 #include <linux/bsg.h>
42 #include <arpa/inet.h>
45 #include "libudev-private.h"
48 #define COMMAND_TIMEOUT_MSEC (30 * 1000)
50 static int disk_scsi_inquiry_command(int fd
,
56 * INQUIRY, see SPC-4 section 6.4
58 [0] = 0x12, /* OPERATION CODE: INQUIRY */
59 [3] = (buf_len
>> 8), /* ALLOCATION LENGTH */
60 [4] = (buf_len
& 0xff),
62 uint8_t sense
[32] = {};
63 struct sg_io_v4 io_v4
= {
65 .protocol
= BSG_PROTOCOL_SCSI
,
66 .subprotocol
= BSG_SUB_PROTOCOL_SCSI_CMD
,
67 .request_len
= sizeof(cdb
),
68 .request
= (uintptr_t) cdb
,
69 .max_response_len
= sizeof(sense
),
70 .response
= (uintptr_t) sense
,
71 .din_xfer_len
= buf_len
,
72 .din_xferp
= (uintptr_t) buf
,
73 .timeout
= COMMAND_TIMEOUT_MSEC
,
77 ret
= ioctl(fd
, SG_IO
, &io_v4
);
79 /* could be that the driver doesn't do version 4, try version 3 */
80 if (errno
== EINVAL
) {
81 struct sg_io_hdr io_hdr
= {
83 .cmdp
= (unsigned char*) cdb
,
84 .cmd_len
= sizeof (cdb
),
88 .mx_sb_len
= sizeof(sense
),
89 .dxfer_direction
= SG_DXFER_FROM_DEV
,
90 .timeout
= COMMAND_TIMEOUT_MSEC
,
93 ret
= ioctl(fd
, SG_IO
, &io_hdr
);
97 /* even if the ioctl succeeds, we need to check the return value */
98 if (!(io_hdr
.status
== 0 &&
99 io_hdr
.host_status
== 0 &&
100 io_hdr
.driver_status
== 0)) {
108 /* even if the ioctl succeeds, we need to check the return value */
109 if (!(io_v4
.device_status
== 0 &&
110 io_v4
.transport_status
== 0 &&
111 io_v4
.driver_status
== 0)) {
119 static int disk_identify_command(int fd
,
125 * ATA Pass-Through 12 byte command, as described in
127 * T10 04-262r8 ATA Command Pass-Through
129 * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf
131 [0] = 0xa1, /* OPERATION CODE: 12 byte pass through */
132 [1] = 4 << 1, /* PROTOCOL: PIO Data-in */
133 [2] = 0x2e, /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */
134 [3] = 0, /* FEATURES */
135 [4] = 1, /* SECTORS */
136 [5] = 0, /* LBA LOW */
137 [6] = 0, /* LBA MID */
138 [7] = 0, /* LBA HIGH */
139 [8] = 0 & 0x4F, /* SELECT */
140 [9] = 0xEC, /* Command: ATA IDENTIFY DEVICE */
142 uint8_t sense
[32] = {};
143 uint8_t *desc
= sense
+ 8;
144 struct sg_io_v4 io_v4
= {
146 .protocol
= BSG_PROTOCOL_SCSI
,
147 .subprotocol
= BSG_SUB_PROTOCOL_SCSI_CMD
,
148 .request_len
= sizeof(cdb
),
149 .request
= (uintptr_t) cdb
,
150 .max_response_len
= sizeof(sense
),
151 .response
= (uintptr_t) sense
,
152 .din_xfer_len
= buf_len
,
153 .din_xferp
= (uintptr_t) buf
,
154 .timeout
= COMMAND_TIMEOUT_MSEC
,
158 ret
= ioctl(fd
, SG_IO
, &io_v4
);
160 /* could be that the driver doesn't do version 4, try version 3 */
161 if (errno
== EINVAL
) {
162 struct sg_io_hdr io_hdr
= {
164 .cmdp
= (unsigned char*) cdb
,
165 .cmd_len
= sizeof (cdb
),
167 .dxfer_len
= buf_len
,
169 .mx_sb_len
= sizeof (sense
),
170 .dxfer_direction
= SG_DXFER_FROM_DEV
,
171 .timeout
= COMMAND_TIMEOUT_MSEC
,
174 ret
= ioctl(fd
, SG_IO
, &io_hdr
);
181 if (!(sense
[0] == 0x72 && desc
[0] == 0x9 && desc
[1] == 0x0c)) {
189 static int disk_identify_packet_device_command(int fd
,
195 * ATA Pass-Through 16 byte command, as described in
197 * T10 04-262r8 ATA Command Pass-Through
199 * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf
201 [0] = 0x85, /* OPERATION CODE: 16 byte pass through */
202 [1] = 4 << 1, /* PROTOCOL: PIO Data-in */
203 [2] = 0x2e, /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */
204 [3] = 0, /* FEATURES */
205 [4] = 0, /* FEATURES */
206 [5] = 0, /* SECTORS */
207 [6] = 1, /* SECTORS */
208 [7] = 0, /* LBA LOW */
209 [8] = 0, /* LBA LOW */
210 [9] = 0, /* LBA MID */
211 [10] = 0, /* LBA MID */
212 [11] = 0, /* LBA HIGH */
213 [12] = 0, /* LBA HIGH */
214 [13] = 0, /* DEVICE */
215 [14] = 0xA1, /* Command: ATA IDENTIFY PACKET DEVICE */
216 [15] = 0, /* CONTROL */
218 uint8_t sense
[32] = {};
219 uint8_t *desc
= sense
+ 8;
220 struct sg_io_v4 io_v4
= {
222 .protocol
= BSG_PROTOCOL_SCSI
,
223 .subprotocol
= BSG_SUB_PROTOCOL_SCSI_CMD
,
224 .request_len
= sizeof (cdb
),
225 .request
= (uintptr_t) cdb
,
226 .max_response_len
= sizeof (sense
),
227 .response
= (uintptr_t) sense
,
228 .din_xfer_len
= buf_len
,
229 .din_xferp
= (uintptr_t) buf
,
230 .timeout
= COMMAND_TIMEOUT_MSEC
,
234 ret
= ioctl(fd
, SG_IO
, &io_v4
);
236 /* could be that the driver doesn't do version 4, try version 3 */
237 if (errno
== EINVAL
) {
238 struct sg_io_hdr io_hdr
= {
240 .cmdp
= (unsigned char*) cdb
,
241 .cmd_len
= sizeof (cdb
),
243 .dxfer_len
= buf_len
,
245 .mx_sb_len
= sizeof (sense
),
246 .dxfer_direction
= SG_DXFER_FROM_DEV
,
247 .timeout
= COMMAND_TIMEOUT_MSEC
,
250 ret
= ioctl(fd
, SG_IO
, &io_hdr
);
257 if (!(sense
[0] == 0x72 && desc
[0] == 0x9 && desc
[1] == 0x0c)) {
266 * disk_identify_get_string:
267 * @identify: A block of IDENTIFY data
268 * @offset_words: Offset of the string to get, in words.
269 * @dest: Destination buffer for the string.
270 * @dest_len: Length of destination buffer, in bytes.
272 * Copies the ATA string from @identify located at @offset_words into @dest.
274 static void disk_identify_get_string(uint8_t identify
[512],
275 unsigned int offset_words
,
282 while (dest_len
> 0) {
283 c1
= identify
[offset_words
* 2 + 1];
284 c2
= identify
[offset_words
* 2];
294 static void disk_identify_fixup_string(uint8_t identify
[512],
295 unsigned int offset_words
,
298 disk_identify_get_string(identify
, offset_words
,
299 (char *) identify
+ offset_words
* 2, len
);
302 static void disk_identify_fixup_uint16 (uint8_t identify
[512], unsigned int offset_words
)
306 p
= (uint16_t *) identify
;
307 p
[offset_words
] = le16toh (p
[offset_words
]);
312 * @udev: The libudev context.
313 * @fd: File descriptor for the block device.
314 * @out_identify: Return location for IDENTIFY data.
315 * @out_is_packet_device: Return location for whether returned data is from a IDENTIFY PACKET DEVICE.
317 * Sends the IDENTIFY DEVICE or IDENTIFY PACKET DEVICE command to the
318 * device represented by @fd. If successful, then the result will be
319 * copied into @out_identify and @out_is_packet_device.
321 * This routine is based on code from libatasmart, Copyright 2008
322 * Lennart Poettering, LGPL v2.1.
324 * Returns: 0 if the data was successfully obtained, otherwise
325 * non-zero with errno set.
327 static int disk_identify(struct udev
*udev
,
329 uint8_t out_identify
[512],
330 int *out_is_packet_device
)
333 uint8_t inquiry_buf
[36];
334 int peripheral_device_type
;
337 int is_packet_device
= 0;
340 memzero(out_identify
, 512);
342 /* If we were to use ATA PASS_THROUGH (12) on an ATAPI device
343 * we could accidentally blank media. This is because MMC's BLANK
344 * command has the same op-code (0x61).
346 * To prevent this from happening we bail out if the device
347 * isn't a Direct Access Block Device, e.g. SCSI type 0x00
348 * (CD/DVD devices are type 0x05). So we send a SCSI INQUIRY
349 * command first... libata is handling this via its SCSI
352 * This also ensures that we're actually dealing with a device
353 * that understands SCSI commands.
355 * (Yes, it is a bit perverse that we're tunneling the ATA
356 * command through SCSI and relying on the ATA driver
357 * emulating SCSI well-enough...)
359 * (See commit 160b069c25690bfb0c785994c7c3710289179107 for
360 * the original bug-fix and see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=556635
361 * for the original bug-report.)
363 ret
= disk_scsi_inquiry_command (fd
, inquiry_buf
, sizeof (inquiry_buf
));
367 /* SPC-4, section 6.4.2: Standard INQUIRY data */
368 peripheral_device_type
= inquiry_buf
[0] & 0x1f;
369 if (peripheral_device_type
== 0x05)
371 is_packet_device
= 1;
372 ret
= disk_identify_packet_device_command(fd
, out_identify
, 512);
373 goto check_nul_bytes
;
375 if (peripheral_device_type
!= 0x00) {
381 /* OK, now issue the IDENTIFY DEVICE command */
382 ret
= disk_identify_command(fd
, out_identify
, 512);
387 /* Check if IDENTIFY data is all NUL bytes - if so, bail */
389 for (n
= 0; n
< 512; n
++) {
390 if (out_identify
[n
] != '\0') {
403 if (out_is_packet_device
!= NULL
)
404 *out_is_packet_device
= is_packet_device
;
409 static void log_fn(struct udev
*udev
, int priority
,
410 const char *file
, int line
, const char *fn
,
411 const char *format
, va_list args
)
413 log_metav(priority
, file
, line
, fn
, format
, args
);
416 int main(int argc
, char *argv
[])
419 struct hd_driveid id
;
420 uint8_t identify
[512];
421 uint16_t *identify_words
;
426 const char *node
= NULL
;
431 int is_packet_device
= 0;
432 static const struct option options
[] = {
433 { "export", no_argument
, NULL
, 'x' },
434 { "help", no_argument
, NULL
, 'h' },
438 log_parse_environment();
445 udev_set_log_fn(udev
, log_fn
);
450 option
= getopt_long(argc
, argv
, "xh", options
, NULL
);
459 printf("Usage: ata_id [--export] [--help] <device>\n"
460 " --export print values as environment keys\n"
461 " --help print this help text\n\n");
468 log_error("no node specified");
473 fd
= open(node
, O_RDONLY
|O_NONBLOCK
|O_CLOEXEC
);
475 log_error("unable to open '%s'", node
);
480 if (disk_identify(udev
, fd
, identify
, &is_packet_device
) == 0) {
482 * fix up only the fields from the IDENTIFY data that we are going to
483 * use and copy it into the hd_driveid struct for convenience
485 disk_identify_fixup_string(identify
, 10, 20); /* serial */
486 disk_identify_fixup_string(identify
, 23, 8); /* fwrev */
487 disk_identify_fixup_string(identify
, 27, 40); /* model */
488 disk_identify_fixup_uint16(identify
, 0); /* configuration */
489 disk_identify_fixup_uint16(identify
, 75); /* queue depth */
490 disk_identify_fixup_uint16(identify
, 75); /* SATA capabilities */
491 disk_identify_fixup_uint16(identify
, 82); /* command set supported */
492 disk_identify_fixup_uint16(identify
, 83); /* command set supported */
493 disk_identify_fixup_uint16(identify
, 84); /* command set supported */
494 disk_identify_fixup_uint16(identify
, 85); /* command set supported */
495 disk_identify_fixup_uint16(identify
, 86); /* command set supported */
496 disk_identify_fixup_uint16(identify
, 87); /* command set supported */
497 disk_identify_fixup_uint16(identify
, 89); /* time required for SECURITY ERASE UNIT */
498 disk_identify_fixup_uint16(identify
, 90); /* time required for enhanced SECURITY ERASE UNIT */
499 disk_identify_fixup_uint16(identify
, 91); /* current APM values */
500 disk_identify_fixup_uint16(identify
, 94); /* current AAM value */
501 disk_identify_fixup_uint16(identify
, 128); /* device lock function */
502 disk_identify_fixup_uint16(identify
, 217); /* nominal media rotation rate */
503 memcpy(&id
, identify
, sizeof id
);
505 /* If this fails, then try HDIO_GET_IDENTITY */
506 if (ioctl(fd
, HDIO_GET_IDENTITY
, &id
) != 0) {
507 log_debug("HDIO_GET_IDENTITY failed for '%s': %m", node
);
512 identify_words
= (uint16_t *) identify
;
514 memcpy (model
, id
.model
, 40);
516 udev_util_encode_string(model
, model_enc
, sizeof(model_enc
));
517 util_replace_whitespace((char *) id
.model
, model
, 40);
518 util_replace_chars(model
, NULL
);
519 util_replace_whitespace((char *) id
.serial_no
, serial
, 20);
520 util_replace_chars(serial
, NULL
);
521 util_replace_whitespace((char *) id
.fw_rev
, revision
, 8);
522 util_replace_chars(revision
, NULL
);
525 /* Set this to convey the disk speaks the ATA protocol */
526 printf("ID_ATA=1\n");
528 if ((id
.config
>> 8) & 0x80) {
529 /* This is an ATAPI device */
530 switch ((id
.config
>> 8) & 0x1f) {
532 printf("ID_TYPE=cd\n");
535 printf("ID_TYPE=tape\n");
538 printf("ID_TYPE=cd\n");
541 printf("ID_TYPE=optical\n");
544 printf("ID_TYPE=generic\n");
548 printf("ID_TYPE=disk\n");
550 printf("ID_BUS=ata\n");
551 printf("ID_MODEL=%s\n", model
);
552 printf("ID_MODEL_ENC=%s\n", model_enc
);
553 printf("ID_REVISION=%s\n", revision
);
554 if (serial
[0] != '\0') {
555 printf("ID_SERIAL=%s_%s\n", model
, serial
);
556 printf("ID_SERIAL_SHORT=%s\n", serial
);
558 printf("ID_SERIAL=%s\n", model
);
561 if (id
.command_set_1
& (1<<5)) {
562 printf ("ID_ATA_WRITE_CACHE=1\n");
563 printf ("ID_ATA_WRITE_CACHE_ENABLED=%d\n", (id
.cfs_enable_1
& (1<<5)) ? 1 : 0);
565 if (id
.command_set_1
& (1<<10)) {
566 printf("ID_ATA_FEATURE_SET_HPA=1\n");
567 printf("ID_ATA_FEATURE_SET_HPA_ENABLED=%d\n", (id
.cfs_enable_1
& (1<<10)) ? 1 : 0);
570 * TODO: use the READ NATIVE MAX ADDRESS command to get the native max address
571 * so it is easy to check whether the protected area is in use.
574 if (id
.command_set_1
& (1<<3)) {
575 printf("ID_ATA_FEATURE_SET_PM=1\n");
576 printf("ID_ATA_FEATURE_SET_PM_ENABLED=%d\n", (id
.cfs_enable_1
& (1<<3)) ? 1 : 0);
578 if (id
.command_set_1
& (1<<1)) {
579 printf("ID_ATA_FEATURE_SET_SECURITY=1\n");
580 printf("ID_ATA_FEATURE_SET_SECURITY_ENABLED=%d\n", (id
.cfs_enable_1
& (1<<1)) ? 1 : 0);
581 printf("ID_ATA_FEATURE_SET_SECURITY_ERASE_UNIT_MIN=%d\n", id
.trseuc
* 2);
582 if ((id
.cfs_enable_1
& (1<<1))) /* enabled */ {
584 printf("ID_ATA_FEATURE_SET_SECURITY_LEVEL=maximum\n");
586 printf("ID_ATA_FEATURE_SET_SECURITY_LEVEL=high\n");
589 printf("ID_ATA_FEATURE_SET_SECURITY_ENHANCED_ERASE_UNIT_MIN=%d\n", id
.trsEuc
* 2);
591 printf("ID_ATA_FEATURE_SET_SECURITY_EXPIRE=1\n");
593 printf("ID_ATA_FEATURE_SET_SECURITY_FROZEN=1\n");
595 printf("ID_ATA_FEATURE_SET_SECURITY_LOCKED=1\n");
597 if (id
.command_set_1
& (1<<0)) {
598 printf("ID_ATA_FEATURE_SET_SMART=1\n");
599 printf("ID_ATA_FEATURE_SET_SMART_ENABLED=%d\n", (id
.cfs_enable_1
& (1<<0)) ? 1 : 0);
601 if (id
.command_set_2
& (1<<9)) {
602 printf("ID_ATA_FEATURE_SET_AAM=1\n");
603 printf("ID_ATA_FEATURE_SET_AAM_ENABLED=%d\n", (id
.cfs_enable_2
& (1<<9)) ? 1 : 0);
604 printf("ID_ATA_FEATURE_SET_AAM_VENDOR_RECOMMENDED_VALUE=%d\n", id
.acoustic
>> 8);
605 printf("ID_ATA_FEATURE_SET_AAM_CURRENT_VALUE=%d\n", id
.acoustic
& 0xff);
607 if (id
.command_set_2
& (1<<5)) {
608 printf("ID_ATA_FEATURE_SET_PUIS=1\n");
609 printf("ID_ATA_FEATURE_SET_PUIS_ENABLED=%d\n", (id
.cfs_enable_2
& (1<<5)) ? 1 : 0);
611 if (id
.command_set_2
& (1<<3)) {
612 printf("ID_ATA_FEATURE_SET_APM=1\n");
613 printf("ID_ATA_FEATURE_SET_APM_ENABLED=%d\n", (id
.cfs_enable_2
& (1<<3)) ? 1 : 0);
614 if ((id
.cfs_enable_2
& (1<<3)))
615 printf("ID_ATA_FEATURE_SET_APM_CURRENT_VALUE=%d\n", id
.CurAPMvalues
& 0xff);
617 if (id
.command_set_2
& (1<<0))
618 printf("ID_ATA_DOWNLOAD_MICROCODE=1\n");
621 * Word 76 indicates the capabilities of a SATA device. A PATA device shall set
622 * word 76 to 0000h or FFFFh. If word 76 is set to 0000h or FFFFh, then
623 * the device does not claim compliance with the Serial ATA specification and words
624 * 76 through 79 are not valid and shall be ignored.
626 word
= *((uint16_t *) identify
+ 76);
627 if (word
!= 0x0000 && word
!= 0xffff) {
628 printf("ID_ATA_SATA=1\n");
630 * If bit 2 of word 76 is set to one, then the device supports the Gen2
631 * signaling rate of 3.0 Gb/s (see SATA 2.6).
633 * If bit 1 of word 76 is set to one, then the device supports the Gen1
634 * signaling rate of 1.5 Gb/s (see SATA 2.6).
637 printf("ID_ATA_SATA_SIGNAL_RATE_GEN2=1\n");
639 printf("ID_ATA_SATA_SIGNAL_RATE_GEN1=1\n");
642 /* Word 217 indicates the nominal media rotation rate of the device */
643 word
= *((uint16_t *) identify
+ 217);
644 if (word
!= 0x0000) {
645 if (word
== 0x0001) {
646 printf ("ID_ATA_ROTATION_RATE_RPM=0\n"); /* non-rotating e.g. SSD */
647 } else if (word
>= 0x0401 && word
<= 0xfffe) {
648 printf ("ID_ATA_ROTATION_RATE_RPM=%d\n", word
);
653 * Words 108-111 contain a mandatory World Wide Name (WWN) in the NAA IEEE Registered identifier
654 * format. Word 108 bits (15:12) shall contain 5h, indicating that the naming authority is IEEE.
655 * All other values are reserved.
657 word
= *((uint16_t *) identify
+ 108);
658 if ((word
& 0xf000) == 0x5000) {
661 wwwn
= *((uint16_t *) identify
+ 108);
663 wwwn
|= *((uint16_t *) identify
+ 109);
665 wwwn
|= *((uint16_t *) identify
+ 110);
667 wwwn
|= *((uint16_t *) identify
+ 111);
668 printf("ID_WWN=0x%llx\n", (unsigned long long int) wwwn
);
669 /* ATA devices have no vendor extension */
670 printf("ID_WWN_WITH_EXTENSION=0x%llx\n", (unsigned long long int) wwwn
);
673 /* from Linux's include/linux/ata.h */
674 if (identify_words
[0] == 0x848a || identify_words
[0] == 0x844a) {
675 printf("ID_ATA_CFA=1\n");
677 if ((identify_words
[83] & 0xc004) == 0x4004) {
678 printf("ID_ATA_CFA=1\n");
682 if (serial
[0] != '\0')
683 printf("%s_%s\n", model
, serial
);
685 printf("%s\n", model
);