diff mbox

[RFC] sg3_utils: Added hybrid information log utility

Message ID 20141029195720.5225.51331.stgit@stg-AndroidDev-VirtualBox
State Not Applicable
Delegated to: David Miller
Headers show

Commit Message

Jason B. Akers Oct. 29, 2014, 7:57 p.m. UTC
From: Kapil Karkra <kapil.karkra@intel.com>

A solid state hybrid drive (SSHD) is a hard drive with a small embedded
NAND. Host drivers can manage this NAND using the commands defined by
SATA 3.2 standard. One SATA command that provides visibility into the
SSHD's cache behavior is get hybrid log command. This augmentation
allows users to issue the command as follows:

sg_sat_get_hybrid_log /dev/sdc
assuming /dev/sdc is an SSHD.

patch applies to the following sourcebase from where to clone:
https://github.com/hreinecke/sg3_utils.git

Signed-off-by: Kapil Karkra <kapil.karkra@intel.com>
Signed-off-by: Jason B. Akers <jason.b.akers@intel.com>
---
 src/Makefile.am             |   21 ++
 src/sg_sat_get_hybrid_log.c |  419 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 434 insertions(+), 6 deletions(-)
 create mode 100644 src/sg_sat_get_hybrid_log.c


--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Phillip Susi Nov. 25, 2014, 12:33 a.m. UTC | #1
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

On 10/29/2014 03:57 PM, Jason B. Akers wrote:
> From: Kapil Karkra <kapil.karkra@intel.com>
> 
> A solid state hybrid drive (SSHD) is a hard drive with a small
> embedded NAND. Host drivers can manage this NAND using the commands
> defined by SATA 3.2 standard. One SATA command that provides
> visibility into the SSHD's cache behavior is get hybrid log
> command. This augmentation allows users to issue the command as
> follows:
> 
> sg_sat_get_hybrid_log /dev/sdc assuming /dev/sdc is an SSHD.
> 
> patch applies to the following sourcebase from where to clone: 
> https://github.com/hreinecke/sg3_utils.git

I cloned that repo and the patch does not apply cleanly.  git am -3
says the referenced blobs are not found and it has conflicts in
src/Makefile.am.  I manually fixed that up and then it fails to link
due to unresolved externals.



-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBCgAGBQJUc85UAAoJENRVrw2cjl5RR3YIAJOF0fcTkF5pM0OIA87hK8k8
ujwflBTy66ZbPzXMD97cTGYQ6gPp3UCeT/ZcElBfrGGAuD5u/ETXMJY7lqAZgYtK
bELPv6oLhz3ya2IO442sUlRYO4dVfwhsnak+2rLiQkXCy4WKSJ1EYiMIP/VHj8ne
5e8VYkuc0KamKjvT4v6EwJ7tM0blfJbYgmFGruIxOSgCAo94Zp9thAcctb9PbRex
HnPTcnw5cI1sCoLf5fJafhc9w/1H45WjJTnGF7zs4hq/GGsYCwryvI0ovwAzU9ST
R3jRvE+70oiyQDsj9EBak63hRYIAd8QzQ3TkCjaM5E1XHSU7vTnxvxAjKb4ZyF4=
=a8Vh
-----END PGP SIGNATURE-----
--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jason B. Akers Nov. 25, 2014, 7:13 p.m. UTC | #2
Hi Phillip,
It turns out that this patch was based on an old github repository that doesn't appear to be updated. Doug Gilbert reached out after the initial RFC and directed us to his page (http://sg.danny.cz/sg/) where he has updated sg3_utils code.

As we continue to work through the feedback from our SSHD kernel patches, I'm going to follow up with Doug again on sg3_utils.

> -----Original Message-----

> From: Phillip Susi [mailto:psusi@ubuntu.com]

> Sent: Monday, November 24, 2014 4:34 PM

> To: Akers, Jason B; linux-ide@vger.kernel.org

> Cc: Karkra, Kapil; Williams, Dan J; linux-kernel@vger.kernel.org;

> dgilbert@interlog.com

> Subject: Re: [RFC PATCH] sg3_utils: Added hybrid information log utility

> 

> -----BEGIN PGP SIGNED MESSAGE-----

> Hash: SHA512

> 

> On 10/29/2014 03:57 PM, Jason B. Akers wrote:

> > From: Kapil Karkra <kapil.karkra@intel.com>

> >

> > A solid state hybrid drive (SSHD) is a hard drive with a small

> > embedded NAND. Host drivers can manage this NAND using the

> commands

> > defined by SATA 3.2 standard. One SATA command that provides

> > visibility into the SSHD's cache behavior is get hybrid log command.

> > This augmentation allows users to issue the command as

> > follows:

> >

> > sg_sat_get_hybrid_log /dev/sdc assuming /dev/sdc is an SSHD.

> >

> > patch applies to the following sourcebase from where to clone:

> > https://github.com/hreinecke/sg3_utils.git

> 

> I cloned that repo and the patch does not apply cleanly.  git am -3 says the

> referenced blobs are not found and it has conflicts in src/Makefile.am.  I

> manually fixed that up and then it fails to link due to unresolved externals.

> 

> 

> 

> -----BEGIN PGP SIGNATURE-----

> Version: GnuPG v1

> 

> iQEcBAEBCgAGBQJUc85UAAoJENRVrw2cjl5RR3YIAJOF0fcTkF5pM0OIA87hK8k

> 8

> ujwflBTy66ZbPzXMD97cTGYQ6gPp3UCeT/ZcElBfrGGAuD5u/ETXMJY7lqAZgYt

> K

> bELPv6oLhz3ya2IO442sUlRYO4dVfwhsnak+2rLiQkXCy4WKSJ1EYiMIP/VHj8ne

> 5e8VYkuc0KamKjvT4v6EwJ7tM0blfJbYgmFGruIxOSgCAo94Zp9thAcctb9PbRex

> HnPTcnw5cI1sCoLf5fJafhc9w/1H45WjJTnGF7zs4hq/GGsYCwryvI0ovwAzU9ST

> R3jRvE+70oiyQDsj9EBak63hRYIAd8QzQ3TkCjaM5E1XHSU7vTnxvxAjKb4ZyF4=

> =a8Vh

> -----END PGP SIGNATURE-----
Douglas Gilbert Nov. 25, 2014, 8:27 p.m. UTC | #3
On 14-11-25 02:13 PM, Akers, Jason B wrote:
> Hi Phillip,
> It turns out that this patch was based on an old github repository that doesn't appear to be updated. Doug Gilbert reached out after the initial RFC and directed us to his page (http://sg.danny.cz/sg/) where he has updated sg3_utils code.
>
> As we continue to work through the feedback from our SSHD kernel patches, I'm going to follow up with Doug again on sg3_utils.

Hi,
As discussed earlier in this thread adding a new utility
for each log page like sg_sat_get_hybrid_log would lead to
hundreds of utilities. There are now these groups of
storage related pages (with user space utilities to decode
them shown in parentheses):
   - SCSI VPD pages  (sg_vpd (sdparm and legacy sg_inq))
   - SCSI mode pages (sdparm and sg_modes)
   - SCSI log pages  (sg_logs)
   - ATA GP log pages (from 1.40 sg_sat_read_gplog)
   - ATA SMART log pages (smartctl)

At the start of this thread the proposed patch was very
close to the release of sg3_utils version 1.40 and Hannes
Reinecke contributed a more general approach:
sg_sat_read_gplog which I did incorporate. Currently it
only decodes pages to hex.

Please look at that utility (i.e. sg_sat_read_gplog) as the
basis for adding ATA GP log page decoding such as the SATA
hybrid information page. Please send patches against its source.

Doug Gilbert


>> -----Original Message-----
>> From: Phillip Susi [mailto:psusi@ubuntu.com]
>> Sent: Monday, November 24, 2014 4:34 PM
>> To: Akers, Jason B; linux-ide@vger.kernel.org
>> Cc: Karkra, Kapil; Williams, Dan J; linux-kernel@vger.kernel.org;
>> dgilbert@interlog.com
>> Subject: Re: [RFC PATCH] sg3_utils: Added hybrid information log utility
>>
>> -----BEGIN PGP SIGNED MESSAGE-----
>> Hash: SHA512
>>
>> On 10/29/2014 03:57 PM, Jason B. Akers wrote:
>>> From: Kapil Karkra <kapil.karkra@intel.com>
>>>
>>> A solid state hybrid drive (SSHD) is a hard drive with a small
>>> embedded NAND. Host drivers can manage this NAND using the
>> commands
>>> defined by SATA 3.2 standard. One SATA command that provides
>>> visibility into the SSHD's cache behavior is get hybrid log command.
>>> This augmentation allows users to issue the command as
>>> follows:
>>>
>>> sg_sat_get_hybrid_log /dev/sdc assuming /dev/sdc is an SSHD.
>>>
>>> patch applies to the following sourcebase from where to clone:
>>> https://github.com/hreinecke/sg3_utils.git
>>
>> I cloned that repo and the patch does not apply cleanly.  git am -3 says the
>> referenced blobs are not found and it has conflicts in src/Makefile.am.  I
>> manually fixed that up and then it fails to link due to unresolved externals.
>>
>>
>>
>> -----BEGIN PGP SIGNATURE-----
>> Version: GnuPG v1
>>
>> iQEcBAEBCgAGBQJUc85UAAoJENRVrw2cjl5RR3YIAJOF0fcTkF5pM0OIA87hK8k
>> 8
>> ujwflBTy66ZbPzXMD97cTGYQ6gPp3UCeT/ZcElBfrGGAuD5u/ETXMJY7lqAZgYt
>> K
>> bELPv6oLhz3ya2IO442sUlRYO4dVfwhsnak+2rLiQkXCy4WKSJ1EYiMIP/VHj8ne
>> 5e8VYkuc0KamKjvT4v6EwJ7tM0blfJbYgmFGruIxOSgCAo94Zp9thAcctb9PbRex
>> HnPTcnw5cI1sCoLf5fJafhc9w/1H45WjJTnGF7zs4hq/GGsYCwryvI0ovwAzU9ST
>> R3jRvE+70oiyQDsj9EBak63hRYIAd8QzQ3TkCjaM5E1XHSU7vTnxvxAjKb4ZyF4=
>> =a8Vh
>> -----END PGP SIGNATURE-----

--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Phillip Susi Dec. 16, 2014, 12:46 a.m. UTC | #4
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

On 11/25/2014 02:13 PM, Akers, Jason B wrote:
> Hi Phillip, It turns out that this patch was based on an old
> github repository that doesn't appear to be updated. Doug Gilbert
> reached out after the initial RFC and directed us to his page 
> (http://sg.danny.cz/sg/) where he has updated sg3_utils code.
> 
> As we continue to work through the feedback from our SSHD kernel 
> patches, I'm going to follow up with Doug again on sg3_utils.

So is there a set of patches that applies to a release from that web
site?  Also is the source only released as tarballs?  There is no
source repo?

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBCgAGBQJUj4DKAAoJENRVrw2cjl5RwEwH/147w+N+z9r3J70AQrLdXgtN
mRF2VLEK/v0l7rpnnyiKyL7Trjc3/YXY9tLf3feC225l9UL6K73moLKGWMI+iRU2
xvCWIJKHQyf8E/j6qFqid0G9V/IQNG9vXAZSEmrTcvT5NaEJ0U3kSCKe5w9xEYEE
6SLYTF+FRHkXceloFvW/8PAwj/2K4g/KsZShIS07kdzAh+fIoZM6qQP3XbEK5v1T
x+zuFZtIVzVglQmQWF6wAn5pBjHGNLCA1Yw1+Lx3tuJCoVv1B5ze1k0FOnWu6xOQ
bjeOQ0cgZOjYGjgywhoJn5hgKxOhfXsNsIhSSqA/SNky4vMOV5gRXKjA2WgHu6g=
=7jVR
-----END PGP SIGNATURE-----
--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Phillip Susi March 24, 2015, 2:27 a.m. UTC | #5
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

On 12/15/2014 07:46 PM, Phillip Susi wrote:
> On 11/25/2014 02:13 PM, Akers, Jason B wrote:
>> Hi Phillip, It turns out that this patch was based on an old 
>> github repository that doesn't appear to be updated. Doug
>> Gilbert reached out after the initial RFC and directed us to his
>> page (http://sg.danny.cz/sg/) where he has updated sg3_utils
>> code.
> 
>> As we continue to work through the feedback from our SSHD kernel
>>  patches, I'm going to follow up with Doug again on sg3_utils.
> 
> So is there a set of patches that applies to a release from that
> web site?  Also is the source only released as tarballs?  There is
> no source repo?

Hello.  I am still beta testing an SSHD drive and would very much like
to get some more information out of its logs and/or manipulate the
cache pinned working set.  Is there somewhere I can get these patched
utilities yet?

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBCgAGBQJVEMt2AAoJENRVrw2cjl5RR7AH/iOPMYRoT1/gdpdVlbIfCsWw
kP9MnaWVTcqT3O1rgKbudFuMqcJGD/ScnZOIsowdnJkKxwWyGUq7w863GFtaPOul
o4DBWqLYPYFbmbsgs/meiS3I2qyFrUNGYL0Db8H2mQ2bbaXg59hJ4gO00eSvf8Zm
gMOu3njcs3REEfu/QDi2pfJXXlWMAQfgUUomxdGb1HHmnQqR7YGAdakfRXOXfNHk
Feu2QtdZTLZPkBYkcNDM22yPDSYOb6LbpbuNTYFUfPfHp8X8aejAV8zdtZx5aH7C
ZNA3DEejFqlOltT1fcgTTSb0U0WV/ZcvfTH4g9FCUfx5HOnTI5Oz86He1OthbR0=
=YMQp
-----END PGP SIGNATURE-----
--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Douglas Gilbert March 24, 2015, 7:07 p.m. UTC | #6
On 15-03-23 10:27 PM, Phillip Susi wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA512
>
> On 12/15/2014 07:46 PM, Phillip Susi wrote:
>> On 11/25/2014 02:13 PM, Akers, Jason B wrote:
>>> Hi Phillip, It turns out that this patch was based on an old
>>> github repository that doesn't appear to be updated. Doug
>>> Gilbert reached out after the initial RFC and directed us to his
>>> page (http://sg.danny.cz/sg/) where he has updated sg3_utils
>>> code.
>>
>>> As we continue to work through the feedback from our SSHD kernel
>>>   patches, I'm going to follow up with Doug again on sg3_utils.
>>
>> So is there a set of patches that applies to a release from that
>> web site?  Also is the source only released as tarballs?  There is
>> no source repo?
>
> Hello.  I am still beta testing an SSHD drive and would very much like
> to get some more information out of its logs and/or manipulate the
> cache pinned working set.  Is there somewhere I can get these patched
> utilities yet?

As discussed in another thread on the subject, the
sg_sat_read_gplog utility was added in the most recent
release of the package:
   http://sg.danny.cz/sg/p/sg3_utils-1.40.tar.xz

as a framework for adding ATA and SATA general purpose log
pages. This approach is consistent with the way the package
has one utility for all SCSI logs pages: sg_logs.

So if you or anyone else wants support for ATA log pages
in sg3_utils, could you please send me patches against the
sg_sat_read_gplog utility.

Doug Gilbert




--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/src/Makefile.am b/src/Makefile.am
index de14608..3f8e052 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -14,7 +14,8 @@  bin_PROGRAMS = \
 	sg_raw sg_rbuf sg_rdac sg_read sg_readcap sg_read_block_limits \
 	sg_read_buffer sg_read_long sg_reassign sg_referrals \
 	sg_requests sg_reset sg_rmsn sg_rtpg sg_safte sg_sat_identify \
-	sg_sat_phy_event sg_sat_set_features sg_scan sg_senddiag sg_ses \
+	sg_sat_phy_event sg_sat_set_features sg_sat_get_hybrid_log \
+	sg_scan sg_senddiag sg_ses \
 	sg_start sg_stpg sg_sync sg_test_rwbuf sg_turs sg_unmap sg_verify \
 	sg_vpd sg_write_buffer sg_write_long sg_write_same sg_wr_mode \
 	sg_xcopy sg_copy_results
@@ -36,7 +37,8 @@  bin_PROGRAMS = \
 	sg_prevent sg_raw sg_rdac sg_readcap sg_read_block_limits \
 	sg_read_buffer sg_read_long sg_reassign sg_referrals sg_requests \
 	sg_rmsn sg_rtpg sg_safte sg_sat_identify sg_sat_phy_event \
-	sg_sat_set_features sg_scan sg_senddiag sg_ses sg_start sg_stpg \
+	sg_sat_set_features sg_sat_get_hybrid_log \
+	sg_scan sg_senddiag sg_ses sg_start sg_stpg \
 	sg_sync sg_turs sg_unmap sg_verify sg_vpd sg_write_buffer \
 	sg_write_long sg_write_same sg_wr_mode
 
@@ -57,7 +59,8 @@  bin_PROGRAMS = \
 	sg_prevent sg_raw sg_rdac sg_readcap sg_read_block_limits \
 	sg_read_buffer sg_read_long sg_reassign sg_referrals sg_requests \
 	sg_rmsn sg_rtpg sg_safte sg_sat_identify sg_sat_phy_event \
-	sg_sat_set_features sg_scan sg_senddiag sg_ses sg_start sg_stpg \
+	sg_sat_set_features sg_sat_get_hybrid_log sg_scan sg_senddiag sg_ses \
+	sg_start sg_stpg \
 	sg_sync sg_turs sg_unmap sg_verify sg_vpd sg_write_buffer \
 	sg_write_long sg_write_same sg_wr_mode
 
@@ -78,7 +81,8 @@  bin_PROGRAMS = \
 	sg_prevent sg_raw sg_rdac sg_readcap sg_read_block_limits \
 	sg_read_buffer sg_read_long sg_reassign sg_referrals sg_requests \
 	sg_rmsn sg_rtpg sg_safte sg_sat_identify sg_sat_phy_event \
-	sg_sat_set_features sg_senddiag sg_ses sg_start sg_stpg \
+	sg_sat_set_features sg_sat_get_hybrid_log \
+	sg_senddiag sg_ses sg_start sg_stpg \
 	sg_sync sg_turs sg_unmap sg_verify sg_vpd sg_write_buffer \
 	sg_write_long sg_write_same sg_wr_mode
 
@@ -93,7 +97,8 @@  bin_PROGRAMS = \
 	sg_prevent sg_raw sg_rdac sg_readcap sg_read_block_limits \
 	sg_read_buffer sg_read_long sg_reassign sg_referrals sg_requests \
 	sg_rmsn sg_rtpg sg_safte sg_sat_identify sg_sat_phy_event \
-	sg_sat_set_features sg_senddiag sg_ses sg_start sg_stpg \
+	sg_sat_set_features sg_sat_get_hybrid_log \
+	sg_senddiag sg_ses sg_start sg_stpg \
 	sg_sync sg_turs sg_unmap sg_verify sg_vpd sg_write_buffer \
 	sg_write_long sg_write_same sg_wr_mode
 
@@ -108,7 +113,8 @@  bin_PROGRAMS = \
 	sg_prevent sg_raw sg_rdac sg_readcap sg_read_block_limits \
 	sg_read_buffer sg_read_long sg_reassign sg_referrals sg_requests \
 	sg_rmsn sg_rtpg sg_safte sg_sat_identify sg_sat_phy_event \
-	sg_sat_set_features sg_senddiag sg_ses sg_start sg_stpg \
+	sg_sat_set_features sg_sat_get_hybrid_log sg_senddiag \
+	sg_ses sg_start sg_stpg \
 	sg_sync sg_turs sg_unmap sg_verify sg_vpd sg_write_buffer \
 	sg_write_long sg_write_same sg_wr_mode
 
@@ -229,6 +235,9 @@  sg_sat_phy_event_LDADD = ../lib/libsgutils2.la @os_libs@
 sg_sat_set_features_SOURCES = sg_sat_set_features.c
 sg_sat_set_features_LDADD = ../lib/libsgutils2.la @os_libs@
 
+sg_sat_get_hybrid_log_SOURCES = sg_sat_get_hybrid_log.c
+sg_sat_get_hybrid_log_LDADD = ../lib/libsgutils2.la @os_libs@
+
 sg_scan_SOURCES = sg_scan.c
 sg_scan_LDADD = ../lib/libsgutils2.la @os_libs@
 
diff --git a/src/sg_sat_get_hybrid_log.c b/src/sg_sat_get_hybrid_log.c
new file mode 100644
index 0000000..909984e
--- /dev/null
+++ b/src/sg_sat_get_hybrid_log.c
@@ -0,0 +1,419 @@ 
+/*
+ * Copyright (c) 2014 Kapil Karkra.
+ * All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the BSD_LICENSE file.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "sg_lib.h"
+#include "sg_cmds_basic.h"
+#include "sg_cmds_extra.h"
+
+static const char * version_str = "1.03 20130507";
+
+/* This program uses a ATA PASS-THROUGH SCSI command. This usage is
+ * defined in the SCSI to ATA Translation (SAT) drafts and standards.
+ * See http://www.t10.org for drafts. SAT is a standard: SAT ANSI INCITS
+ * 431-2007 (draft prior to that is sat-r09.pdf). SAT-2 is also a
+ * standard: SAT-2 ANSI INCITS 465-2010 and the draft prior to that is
+ * sat2r09.pdf . The SAT-3 project has started and the most recent draft
+ * is sat3r01.pdf .
+ */
+
+/* This program uses a ATA PASS-THROUGH (16 or 12) SCSI command defined
+ * by SAT to package an ATA READ LOG EXT (2Fh) command to fetch
+ * log page 14h. That page contains SATA hybrid information log.
+ * For ATA READ LOG EXT command see ATA-8/ACS at www.t13.org .
+ * For SATA Hybrid information log see SATA 3.2 .
+ *
+ * Invocation: see the usage() function below
+ */
+
+#define SAT_ATA_PASS_THROUGH16 0x85
+#define SAT_ATA_PASS_THROUGH16_LEN 16
+#define SAT_ATA_PASS_THROUGH12 0xa1     /* clashes with MMC BLANK comand */
+#define SAT_ATA_PASS_THROUGH12_LEN 12
+#define SAT_ATA_RETURN_DESC 9  /* ATA Return (sense) Descriptor */
+#define ASCQ_ATA_PT_INFO_AVAILABLE 0x1d
+
+#define ATA_READ_LOG_EXT 0x2f
+#define SATA_HYBRID_INFO_LPAGE 0x14
+#define READ_LOG_EXT_RESPONSE_LEN 512
+
+#define DEF_TIMEOUT 20
+
+#define EBUFF_SZ 256
+
+static struct option long_options[] = {
+        {"ck_cond", no_argument, 0, 'c'},
+        {"extend", no_argument, 0, 'e'},
+        {"hex", no_argument, 0, 'H'},
+        {"ignore", no_argument, 0, 'i'},
+        {"len", no_argument, 0, 'l'},
+        {"raw", no_argument, 0, 'r'},
+        {"reset", no_argument, 0, 'R'},
+        {"verbose", no_argument, 0, 'v'},
+        {"version", no_argument, 0, 'V'},
+        {0, 0, 0, 0},
+};
+
+static void
+usage()
+{
+    fprintf(stderr, "Usage: "
+          "sg_sat_get_hybrid_log [--ck_cond] [--extend] [--help] [--hex] "
+          "[--ignore]\n"
+          "                        [--len=16|12] [--raw] [--reset] "
+          "[--verbose]\n"
+          "                        [--version] DEVICE\n"
+          "  where:\n"
+          "    --ck_cond|-c    sets ck_cond bit in cdb (def: 0)\n"
+          "    --extend|-e     sets extend bit in cdb (def: 0)\n"
+          "    --help|-h       print this usage message then exit\n"
+          "    --hex|-H        output response in hex bytes, use twice for\n"
+          "                    hex words\n"
+          "    --ignore|-i     ignore identifier names, output id value "
+          "instead\n"
+          "    --len=16|12 | -l 16|12    cdb length: 16 or 12 bytes "
+          "(default: 16)\n"
+          "    --raw|-r        output response in binary to stdout\n"
+          "    --reset|-R      reset counters (after read)\n"
+          "    --verbose|-v    increase verbosity\n"
+          "    --version|-V    print version string then exit\n\n"
+          "Sends an ATA READ LOG EXT command via a SAT pass through to "
+          "fetch\nlog page 14h which contains SATA Hybrid Information Log\n");
+}
+
+static void
+dStrRaw(const char* str, int len)
+{
+    int k;
+
+    for (k = 0 ; k < len; ++k)
+        printf("%c", str[k]);
+}
+
+/* ATA READ LOG EXT command [2Fh, PIO data-in] */
+/* N.B. "log_addr" is the log page number, "page_in_log" is usually zero */
+static int
+do_read_log_ext(int sg_fd, int log_addr, int page_in_log, int feature,
+                int blk_count, void * resp, int mx_resp_len, int cdb_len,
+                int ck_cond, int extend, int do_hex, int do_raw, int verbose)
+{
+    int ok, res, ret;
+    int protocol = 4;   /* PIO data-in */
+    int t_dir = 1;      /* 0 -> to device, 1 -> from device */
+    int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */
+    int t_length = 2;   /* 0 -> no data transferred, 2 -> sector count */
+    int resid = 0;
+    int got_ard = 0;    /* got ATA result descriptor */
+    int sb_sz;
+    struct sg_scsi_sense_hdr ssh;
+    unsigned char sense_buffer[64];
+    unsigned char ata_return_desc[16];
+    unsigned char aptCmdBlk[SAT_ATA_PASS_THROUGH16_LEN] =
+                {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0,
+                 0, 0, 0, 0, 0, 0, 0, 0};
+    unsigned char apt12CmdBlk[SAT_ATA_PASS_THROUGH12_LEN] =
+                {SAT_ATA_PASS_THROUGH12, 0, 0, 0, 0, 0, 0, 0,
+                 0, 0, 0, 0};
+
+    sb_sz = sizeof(sense_buffer);
+    memset(sense_buffer, 0, sb_sz);
+    memset(ata_return_desc, 0, sizeof(ata_return_desc));
+    ok = 0;
+    if (SAT_ATA_PASS_THROUGH16_LEN == cdb_len) {
+        /* Prepare ATA PASS-THROUGH COMMAND (16) command */
+        aptCmdBlk[3] = (feature >> 8) & 0xff;   /* feature(15:8) */
+        aptCmdBlk[4] = feature & 0xff;          /* feature(7:0) */
+        aptCmdBlk[5] = (blk_count >> 8) & 0xff; /* sector_count(15:8) */
+        aptCmdBlk[6] = blk_count & 0xff;        /* sector_count(7:0) */
+        aptCmdBlk[8] = log_addr & 0xff;  /* lba_low(7:0) == LBA(7:0) */
+        aptCmdBlk[9] = (page_in_log >> 8) & 0xff;
+                /* lba_mid(15:8) == LBA(39:32) */
+        aptCmdBlk[10] = page_in_log & 0xff; /* lba_mid(7:0) == LBA(15:8) */
+        aptCmdBlk[14] = ATA_READ_LOG_EXT;
+        aptCmdBlk[1] = (protocol << 1) | extend;
+        aptCmdBlk[2] = (ck_cond << 5) | (t_dir << 3) |
+                       (byte_block << 2) | t_length;
+        res = sg_ll_ata_pt(sg_fd, aptCmdBlk, cdb_len, DEF_TIMEOUT, resp,
+                           NULL /* doutp */, mx_resp_len, sense_buffer,
+                           sb_sz, ata_return_desc,
+                           sizeof(ata_return_desc), &resid, verbose);
+    } else {
+        /* Prepare ATA PASS-THROUGH COMMAND (12) command */
+        apt12CmdBlk[3] = feature & 0xff;        /* feature(7:0) */
+        apt12CmdBlk[4] = blk_count & 0xff;        /* sector_count(7:0) */
+        apt12CmdBlk[5] = log_addr & 0xff;  /* lba_low(7:0) == LBA(7:0) */
+        apt12CmdBlk[6] = page_in_log & 0xff; /* lba_mid(7:0) == LBA(15:8) */
+        apt12CmdBlk[9] = ATA_READ_LOG_EXT;
+        apt12CmdBlk[1] = (protocol << 1);
+        apt12CmdBlk[2] = (ck_cond << 5) | (t_dir << 3) |
+                         (byte_block << 2) | t_length;
+        res = sg_ll_ata_pt(sg_fd, apt12CmdBlk, cdb_len, DEF_TIMEOUT, resp,
+                           NULL /* doutp */, mx_resp_len, sense_buffer,
+                           sb_sz, ata_return_desc,
+                           sizeof(ata_return_desc), &resid, verbose);
+    }
+    if (0 == res) {
+        ok = 1;
+        if (verbose > 2)
+            fprintf(stderr, "command completed with SCSI GOOD status\n");
+    } else if ((res > 0) && (res & SAM_STAT_CHECK_CONDITION)) {
+        if (verbose > 1)
+            sg_print_sense("ATA pass through", sense_buffer, sb_sz,
+                           ((verbose > 2) ? 1 : 0));
+        if (sg_scsi_normalize_sense(sense_buffer, sb_sz, &ssh)) {
+            switch (ssh.sense_key) {
+            case SPC_SK_ILLEGAL_REQUEST:
+                if ((0x20 == ssh.asc) && (0x0 == ssh.ascq)) {
+                    ret = SG_LIB_CAT_INVALID_OP;
+                    if (verbose < 2)
+                        fprintf(stderr, "ATA PASS-THROUGH (%d) not "
+                                "supported\n", cdb_len);
+                } else {
+                    ret = SG_LIB_CAT_ILLEGAL_REQ;
+                    if (verbose < 2)
+                        fprintf(stderr, "ATA PASS-THROUGH (%d), bad "
+                                "field in cdb\n", cdb_len);
+                }
+                return ret;
+            case SPC_SK_NO_SENSE:
+            case SPC_SK_RECOVERED_ERROR:
+                if ((0x0 == ssh.asc) &&
+                    (ASCQ_ATA_PT_INFO_AVAILABLE == ssh.ascq)) {
+                    if (SAT_ATA_RETURN_DESC != ata_return_desc[0]) {
+                        if (verbose)
+                            fprintf(stderr, "did not find ATA Return "
+                                    "(sense) Descriptor\n");
+                        return SG_LIB_CAT_RECOVERED;
+                    }
+                    got_ard = 1;
+                    break;
+                } else if (SPC_SK_RECOVERED_ERROR == ssh.sense_key)
+                    return SG_LIB_CAT_RECOVERED;
+                else {
+                    if ((0x0 == ssh.asc) && (0x0 == ssh.ascq))
+                        break;
+                    return SG_LIB_CAT_SENSE;
+                }
+            case SPC_SK_UNIT_ATTENTION:
+                if (verbose < 2)
+                    fprintf(stderr, "ATA PASS-THROUGH (%d), Unit Attention "
+                                "detected\n", cdb_len);
+                return SG_LIB_CAT_UNIT_ATTENTION;
+            case SPC_SK_NOT_READY:
+                if (verbose < 2)
+                    fprintf(stderr, "ATA PASS-THROUGH (%d), device not "
+                                "ready\n", cdb_len);
+                return SG_LIB_CAT_NOT_READY;
+            case SPC_SK_MEDIUM_ERROR:
+            case SPC_SK_HARDWARE_ERROR:
+                if (verbose < 2)
+                    fprintf(stderr, "ATA PASS-THROUGH (%d), medium or "
+                            "hardware error\n", cdb_len);
+                return SG_LIB_CAT_MEDIUM_HARD;
+            case SPC_SK_ABORTED_COMMAND:
+                fprintf(stderr, "Aborted command\n");
+                return SG_LIB_CAT_ABORTED_COMMAND;
+            default:
+                if (verbose < 2)
+                    fprintf(stderr, "ATA PASS-THROUGH (%d), some sense "
+                            "data, use '-v' for more information\n", cdb_len);
+                return SG_LIB_CAT_SENSE;
+            }
+        } else {
+            fprintf(stderr, "CHECK CONDITION without response code ??\n");
+            return SG_LIB_CAT_SENSE;
+        }
+        if (0x72 != (sense_buffer[0] & 0x7f)) {
+            fprintf(stderr, "expected descriptor sense format, response "
+                    "code=0x%x\n", sense_buffer[0]);
+            return SG_LIB_CAT_MALFORMED;
+        }
+    } else if (res > 0) {
+        fprintf(stderr, "Unexpected SCSI status=0x%x\n", res);
+        return SG_LIB_CAT_MALFORMED;
+    } else {
+        fprintf(stderr, "ATA pass through (%d) failed\n", cdb_len);
+        if (verbose < 2)
+            fprintf(stderr, "    try adding '-v' for more information\n");
+        return -1;
+    }
+
+    if ((SAT_ATA_RETURN_DESC == ata_return_desc[0]) && (0 == got_ard))
+        fprintf(stderr, "Seem to have got ATA Result Descriptor but "
+                "it was not indicated\n");
+    if (got_ard) {
+        if (ata_return_desc[3] & 0x4) {
+                fprintf(stderr, "error indication in returned FIS: aborted "
+                        "command\n");
+                return SG_LIB_CAT_ABORTED_COMMAND;
+        }
+        ok = 1;
+    }
+
+    if (ok) { /* output result if ok and --hex or --raw given */
+        if (do_raw)
+            dStrRaw((const char *)resp, mx_resp_len);
+        else if (1 == do_hex)
+            dStrHex((const char *)resp, mx_resp_len, 0);
+        else if (do_hex > 1)
+            dWordHex((const unsigned short *)resp, mx_resp_len / 2, 0,
+                     sg_is_big_endian());
+    }
+    return 0;
+}
+
+
+int main(int argc, char * argv[])
+{
+    int sg_fd, c, k, res;
+    char * device_name = 0;
+    char ebuff[EBUFF_SZ];
+    unsigned char inBuff[READ_LOG_EXT_RESPONSE_LEN];
+    int cdb_len = 16;
+    int hex = 0;
+    int ignore = 0;
+    int raw = 0;
+    int reset = 0;
+    int verbose = 0;
+    int ck_cond = 0;   /* set to 1 to read register(s) back */
+    int extend = 0;
+    int ret = 0;
+    int nvmSize = 0;
+
+    memset(inBuff, 0, sizeof(inBuff));
+    while (1) {
+        int option_index = 0;
+
+        c = getopt_long(argc, argv, "cehHil:rRvV",
+                        long_options, &option_index);
+        if (c == -1)
+            break;
+
+        switch (c) {
+        case 'c':
+            ++ck_cond;
+            break;
+        case 'e':
+            ++extend;
+            break;
+        case 'h':
+        case '?':
+            usage();
+            exit(0);
+        case 'H':
+            ++hex;
+            break;
+        case 'i':
+            ++ignore;
+            break;
+        case 'l':
+           cdb_len = sg_get_num(optarg);
+           if (! ((cdb_len == 12) || (cdb_len == 16))) {
+                fprintf(stderr, "argument to '--len' should be 12 or 16\n");
+                return SG_LIB_SYNTAX_ERROR;
+            }
+            break;
+        case 'r':
+            ++raw;
+            break;
+        case 'R':
+            ++reset;
+            break;
+        case 'v':
+            ++verbose;
+            break;
+        case 'V':
+            fprintf(stderr, "version: %s\n", version_str);
+            exit(0);
+        default:
+            fprintf(stderr, "unrecognised option code %c [0x%x]\n", c, c);
+            usage();
+            return SG_LIB_SYNTAX_ERROR;
+        }
+    }
+    if (optind < argc) {
+        if (NULL == device_name) {
+            device_name = argv[optind];
+            ++optind;
+        }
+        if (optind < argc) {
+            for (; optind < argc; ++optind)
+                fprintf(stderr, "Unexpected extra argument: %s\n",
+                        argv[optind]);
+            usage();
+            return SG_LIB_SYNTAX_ERROR;
+        }
+    }
+    if (0 == device_name) {
+        fprintf(stderr, "no DEVICE name detected\n");
+        usage();
+        return SG_LIB_SYNTAX_ERROR;
+    }
+    if (raw) {
+        if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
+            perror("sg_set_binary_mode");
+            return SG_LIB_FILE_ERROR;
+        }
+    }
+
+    if ((sg_fd = open(device_name, O_RDWR)) < 0) {
+        snprintf(ebuff, EBUFF_SZ,
+                 "sg_sat_get_hybrid_log: error opening file: %s", device_name);
+        perror(ebuff);
+        return SG_LIB_FILE_ERROR;
+    }
+    ret = do_read_log_ext(sg_fd, SATA_HYBRID_INFO_LPAGE, 0 /* page_in_log */,
+                          (reset ? 1 : 0) /* feature */,
+                          1 /* blk_count */, inBuff,
+                          READ_LOG_EXT_RESPONSE_LEN, cdb_len, ck_cond,
+                          extend, hex, raw, verbose);
+
+    if ((0 == ret) && (0 == hex) && (0 == raw)) {
+        printf("SATA hybrid information log:\n");
+	k = 0;
+	printf ("Number of Hybrid Descriptors=%d\n", inBuff[k]&0xF);
+	k = 2;
+	printf ("Enabled=%x\n", inBuff[k++]);
+	printf ("Hybrid Health =%x\n", inBuff[k++]);
+	printf ("Dirty Low Threshold =%x\n", inBuff[k++]);
+	printf ("Dirty High Threshold =%x\n", inBuff[k++]);
+	printf ("Optimal Write Granularity=%x\n", inBuff[k++]);
+	printf ("Maximum Priority Level=%d\n", inBuff[k++]&0xF);
+	k = 16;
+	nvmSize = (inBuff[k] | (inBuff[k+1]<<8) | (inBuff[k+2]<<16) | (inBuff[k+3]<<24) );
+	printf ("NVM Size=%x(%d GigaBytes)\n", nvmSize, nvmSize/(2*1024*1024));
+	
+        for (k = 64; k < 512; k += 16) {
+	  if (inBuff[k]) {
+	    printf ("Hybrid Priority=%d\n", inBuff[k]);
+	    printf ("Consumed NVM Size Fraction=%x\n", inBuff[k+1]);
+	    printf ("Consumed Mapping Resource Fraction=%x\n", inBuff[k+2]);
+	    printf ("Consumed NVM Size For Dirty Fraction=%x\n", inBuff[k+3]);
+	    printf ("Consumed Mapping Resource For Dirty Data Fraction=%x\n", inBuff[k+4]);
+	  }
+	}
+     }
+
+    res = close(sg_fd);
+    if (res < 0) {
+        fprintf(stderr, "close error: %s\n", safe_strerror(-res));
+        if (0 == ret)
+            return SG_LIB_FILE_ERROR;
+    }
+    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
+}