4343#define ATA_PT_12_CMDLEN 12
4444#define ATA_PT_16_CMD 0x85
4545#define ATA_PT_16_CMDLEN 16
46+ #define ATA_PT_32_SA 0x1ff0
47+ #define ATA_PT_32_CMDLEN 32
4648#define FORMAT_UNIT_CMD 0x4
4749#define FORMAT_UNIT_CMDLEN 6
4850#define PERSISTENT_RESERVE_IN_CMD 0x5e
@@ -1531,23 +1533,24 @@ sg_ll_verify16(int sg_fd, int vrprotect, int dpo, int bytchk, uint64_t llba,
15311533 return ret ;
15321534}
15331535
1534- /* Invokes a ATA PASS-THROUGH (12 or 16) SCSI command (SAT). If cdb_len
1535- * is 12 then a ATA PASS-THROUGH (12) command is called. If cdb_len is 16
1536- * then a ATA PASS-THROUGH (16) command is called. If cdb_len is any other
1537- * value -1 is returned. After copying from cdbp to an internal buffer,
1538- * the first byte (i.e. offset 0) is set to 0xa1 if cdb_len is 12; or is
1539- * set to 0x85 if cdb_len is 16. The last byte (offset 11 or offset 15) is
1540- * set to 0x0 in the internal buffer. If timeout_secs <= 0 then the timeout
1541- * is set to 60 seconds. For data in or out transfers set dinp or doutp,
1542- * and dlen to the number of bytes to transfer. If dlen is zero then no data
1543- * transfer is assumed. If sense buffer obtained then it is written to
1544- * sensep, else sensep[0] is set to 0x0. If ATA return descriptor is obtained
1545- * then written to ata_return_dp, else ata_return_dp[0] is set to 0x0. Either
1546- * sensep or ata_return_dp (or both) may be NULL pointers. Returns SCSI
1547- * status value (>= 0) or -1 if other error. Users are expected to check the
1548- * sense buffer themselves. If available the data in resid is written to
1549- * residp. Note in SAT-2 and later, fixed format sense data may be placed in
1550- * *sensep in which case sensep[0]==0x70 .
1536+ /* Invokes a ATA PASS-THROUGH (12, 16 or 32) SCSI command (SAT). This is
1537+ * selected by the cdb_len argument that can take values of 12, 16 or 32
1538+ * only (else -1 is returned). The byte at offset 0 (and bytes 0 to 9
1539+ * inclusive for ATA PT(32)) pointed to be cdbp are ignored and apart from
1540+ * the control byte, the rest is copied into an internal cdb which is then
1541+ * sent to the device. The control byte is byte 11 for ATA PT(12), byte 15
1542+ * for ATA PT(16) and byte 1 for ATA PT(32). If timeout_secs <= 0 then the
1543+ * timeout is set to 60 seconds. For data in or out transfers set dinp or
1544+ * doutp, and dlen to the number of bytes to transfer. If dlen is zero then
1545+ * no data transfer is assumed. If sense buffer obtained then it is written
1546+ * to sensep, else sensep[0] is set to 0x0. If ATA return descriptor is
1547+ * obtained then written to ata_return_dp, else ata_return_dp[0] is set to
1548+ * 0x0. Either sensep or ata_return_dp (or both) may be NULL pointers.
1549+ * Returns SCSI status value (>= 0) or -1 if other error. Users are
1550+ * expected to check the sense buffer themselves. If available the data in
1551+ * resid is written to residp. Note in SAT-2 and later, fixed format sense
1552+ * data may be placed in *sensep in which case sensep[0]==0x70, prior to
1553+ * SAT-2 descriptor sense format was required (i.e. sensep[0]==0x72).
15511554 */
15521555int
15531556sg_ll_ata_pt (int sg_fd , const unsigned char * cdbp , int cdb_len ,
@@ -1557,8 +1560,7 @@ sg_ll_ata_pt(int sg_fd, const unsigned char * cdbp, int cdb_len,
15571560 int * residp , int verbose )
15581561{
15591562 int k , res , slen , duration ;
1560- unsigned char aptCmdBlk [ATA_PT_16_CMDLEN ] =
1561- {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
1563+ unsigned char aptCmdBlk [ATA_PT_32_CMDLEN ];
15621564 unsigned char sense_b [SENSE_BUFF_LEN ];
15631565 unsigned char * sp ;
15641566 const unsigned char * bp ;
@@ -1567,35 +1569,55 @@ sg_ll_ata_pt(int sg_fd, const unsigned char * cdbp, int cdb_len,
15671569 char b [256 ];
15681570 int ret = -1 ;
15691571
1572+ memset (aptCmdBlk , 0 , sizeof (aptCmdBlk ));
15701573 b [0 ] = '\0' ;
1571- cnamep = (12 == cdb_len ) ?
1572- "ATA pass through (12)" : "ATA pass through (16)" ;
1573- if ((NULL == cdbp ) || ((12 != cdb_len ) && (16 != cdb_len ))) {
1574- if (verbose ) {
1575- if (NULL == cdbp )
1576- pr2ws ("%s NULL cdb pointer\n" , cnamep );
1577- else
1578- pr2ws ("cdb_len must be 12 or 16\n" );
1579- }
1574+ switch (cdb_len ) {
1575+ case 12 :
1576+ cnamep = "ATA pass-through(12)" ;
1577+ aptCmdBlk [0 ] = ATA_PT_12_CMD ;
1578+ memcpy (aptCmdBlk + 1 , cdbp + 1 , 10 );
1579+ /* control byte at cdb[11] left at zero */
1580+ break ;
1581+ case 16 :
1582+ cnamep = "ATA pass-through(16)" ;
1583+ aptCmdBlk [0 ] = ATA_PT_16_CMD ;
1584+ memcpy (aptCmdBlk + 1 , cdbp + 1 , 14 );
1585+ /* control byte at cdb[15] left at zero */
1586+ break ;
1587+ case 32 :
1588+ cnamep = "ATA pass-through(32)" ;
1589+ aptCmdBlk [0 ] = SG_VARIABLE_LENGTH_CMD ;
1590+ /* control byte at cdb[1] left at zero */
1591+ aptCmdBlk [7 ] = 0x18 ; /* length starting at next byte */
1592+ sg_put_unaligned_be16 (ATA_PT_32_SA , aptCmdBlk + 8 );
1593+ memcpy (aptCmdBlk + 10 , cdbp + 10 , 32 - 10 );
1594+ break ;
1595+ default :
1596+ pr2ws ("cdb_len must be 12, 16 or 32\n" );
1597+ return -1 ;
1598+ }
1599+ if (NULL == cdbp ) {
1600+ if (verbose )
1601+ pr2ws ("%s NULL cdb pointer\n" , cnamep );
15801602 return -1 ;
15811603 }
1582- aptCmdBlk [0 ] = (12 == cdb_len ) ? ATA_PT_12_CMD : ATA_PT_16_CMD ;
15831604 if (sensep && (max_sense_len >= (int )sizeof (sense_b ))) {
15841605 sp = sensep ;
15851606 slen = max_sense_len ;
15861607 } else {
15871608 sp = sense_b ;
15881609 slen = sizeof (sense_b );
15891610 }
1590- if (12 == cdb_len )
1591- memcpy (aptCmdBlk + 1 , cdbp + 1 , ((cdb_len > 11 ) ? 10 : (cdb_len - 1 )));
1592- else
1593- memcpy (aptCmdBlk + 1 , cdbp + 1 , ((cdb_len > 15 ) ? 14 : (cdb_len - 1 )));
15941611 if (verbose ) {
15951612 pr2ws (" %s cdb: " , cnamep );
1596- for (k = 0 ; k < cdb_len ; ++ k )
1597- pr2ws ("%02x " , aptCmdBlk [k ]);
1598- pr2ws ("\n" );
1613+ if (cdb_len < 32 ) {
1614+ for (k = 0 ; k < cdb_len ; ++ k )
1615+ pr2ws ("%02x " , aptCmdBlk [k ]);
1616+ pr2ws ("\n" );
1617+ } else {
1618+ pr2ws ("\n" );
1619+ dStrHexErr ((const char * )aptCmdBlk , cdb_len , -1 );
1620+ }
15991621 }
16001622 ptvp = construct_scsi_pt_obj ();
16011623 if (NULL == ptvp ) {
0 commit comments