4 * Home page of code is: http://smartmontools.sourceforge.net
6 * Copyright (C) 2006-12 Douglas Gilbert <dgilbert@interlog.com>
7 * Copyright (C) 2009-12 Christian Franke <smartmontools-support@lists.sourceforge.net>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
14 * You should have received a copy of the GNU General Public License
15 * (for example COPYING); if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 * The code in this file is based on the SCSI to ATA Translation (SAT)
19 * draft found at http://www.t10.org . The original draft used for this
20 * code is sat-r08.pdf which is not too far away from becoming a
21 * standard. The SAT commands of interest to smartmontools are the
22 * ATA PASS THROUGH SCSI (16) and ATA PASS THROUGH SCSI (12) defined in
23 * section 12 of that document.
25 * sat-r09.pdf is the most recent, easily accessible draft prior to the
26 * original SAT standard (ANSI INCITS 431-2007). By mid-2009 the second
27 * version of the SAT standard (SAT-2) is nearing standardization. In
28 * their wisdom an incompatible change has been introduced in draft
29 * sat2r08a.pdf in the area of the ATA RETURN DESCRIPTOR. A new "fixed
30 * format" ATA RETURN buffer has been defined (sat2r08b.pdf section
31 * 12.2.7) for the case when DSENSE=0 in the Control mode page.
32 * Unfortunately this is the normal case. If the change stands our
33 * code will need to be extended for this case.
35 * With more transports "hiding" SATA disks (and other S-ATAPI devices)
36 * behind a SCSI command set, accessing special features like SMART
37 * information becomes a challenge. The SAT standard offers ATA PASS
38 * THROUGH commands for special usages. Note that the SAT layer may
39 * be inside a generic OS layer (e.g. libata in linux), in a host
40 * adapter (HA or HBA) firmware, or somewhere on the interconnect
41 * between the host computer and the SATA devices (e.g. a RAID made
42 * of SATA disks and the RAID talks "SCSI" to the host computer).
43 * Note that in the latter case, this code does not solve the
44 * addressing issue (i.e. which SATA disk to address behind the logical
45 * SCSI (RAID) interface).
58 #include "atacmds.h" // ataReadHDIdentity()
59 #include "knowndrives.h" // lookup_usb_device()
61 #include "dev_interface.h"
62 #include "dev_ata_cmd_set.h" // ata_device_with_command_set
63 #include "dev_tunnelled.h" // tunnelled_device<>
65 const char * scsiata_cpp_cvsid
= "$Id: scsiata.cpp 3519 2012-03-06 20:01:44Z chrfranke $";
67 /* This is a slightly stretched SCSI sense "descriptor" format header.
68 The addition is to allow the 0x70 and 0x71 response codes. The idea
69 is to place the salient data of both "fixed" and "descriptor" sense
70 format into one structure to ease application processing.
71 The original sense buffer should be kept around for those cases
72 in which more information is required (e.g. the LBA of a MEDIUM ERROR). */
73 /// Abridged SCSI sense data
74 struct sg_scsi_sense_hdr
{
75 unsigned char response_code
; /* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */
76 unsigned char sense_key
;
82 unsigned char additional_length
;
85 /* Maps the salient data from a sense buffer which is in either fixed or
86 descriptor format into a structure mimicking a descriptor format
87 header (i.e. the first 8 bytes of sense descriptor format).
88 If zero response code returns 0. Otherwise returns 1 and if 'sshp' is
89 non-NULL then zero all fields and then set the appropriate fields in
90 that structure. sshp::additional_length is always 0 for response
91 codes 0x70 and 0x71 (fixed format). */
92 static int sg_scsi_normalize_sense(const unsigned char * sensep
, int sb_len
,
93 struct sg_scsi_sense_hdr
* sshp
);
95 /* Attempt to find the first SCSI sense data descriptor that matches the
96 given 'desc_type'. If found return pointer to start of sense data
97 descriptor; otherwise (including fixed format sense data) returns NULL. */
98 static const unsigned char * sg_scsi_sense_desc_find(const unsigned char * sensep
,
99 int sense_len
, int desc_type
);
101 #define SAT_ATA_PASSTHROUGH_12LEN 12
102 #define SAT_ATA_PASSTHROUGH_16LEN 16
104 #define DEF_SAT_ATA_PASSTHRU_SIZE 16
105 #define ATA_RETURN_DESCRIPTOR 9
108 namespace sat
{ // no need to publish anything, name provided for Doxygen
111 /// Implements ATA by tunnelling through SCSI.
114 : public tunnelled_device
<
115 /*implements*/ ata_device
116 /*by tunnelling through a*/, scsi_device
118 virtual public /*implements*/ scsi_device
121 sat_device(smart_interface
* intf
, scsi_device
* scsidev
,
122 const char * req_type
, int passthrulen
= 0, bool enable_auto
= false);
124 virtual ~sat_device() throw();
126 virtual smart_device
* autodetect_open();
128 virtual bool ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
);
130 virtual bool scsi_pass_through(scsi_cmnd_io
* iop
);
138 sat_device::sat_device(smart_interface
* intf
, scsi_device
* scsidev
,
139 const char * req_type
, int passthrulen
/* = 0 */, bool enable_auto
/* = false */)
140 : smart_device(intf
, scsidev
->get_dev_name(),
141 (enable_auto
? "sat,auto" : "sat"), req_type
),
142 tunnelled_device
<ata_device
, scsi_device
>(scsidev
),
143 m_passthrulen(passthrulen
),
144 m_enable_auto(enable_auto
)
147 hide_ata(); // Start as SCSI, switch to ATA in autodetect_open()
149 hide_scsi(); // ATA always
151 set_info().info_name
= strprintf("%s [%sSAT]", scsidev
->get_info_name(),
152 (enable_auto
? "SCSI/" : ""));
155 sat_device::~sat_device() throw()
160 // cdb[0]: ATA PASS THROUGH (16) SCSI command opcode byte (0x85)
161 // cdb[1]: multiple_count, protocol + extend
162 // cdb[2]: offline, ck_cond, t_dir, byte_block + t_length
163 // cdb[3]: features (15:8)
164 // cdb[4]: features (7:0)
165 // cdb[5]: sector_count (15:8)
166 // cdb[6]: sector_count (7:0)
167 // cdb[7]: lba_low (15:8)
168 // cdb[8]: lba_low (7:0)
169 // cdb[9]: lba_mid (15:8)
170 // cdb[10]: lba_mid (7:0)
171 // cdb[11]: lba_high (15:8)
172 // cdb[12]: lba_high (7:0)
174 // cdb[14]: (ata) command
175 // cdb[15]: control (SCSI, leave as zero)
177 // 24 bit lba (from MSB): cdb[12] cdb[10] cdb[8]
178 // 48 bit lba (from MSB): cdb[11] cdb[9] cdb[7] cdb[12] cdb[10] cdb[8]
181 // cdb[0]: ATA PASS THROUGH (12) SCSI command opcode byte (0xa1)
182 // cdb[1]: multiple_count, protocol + extend
183 // cdb[2]: offline, ck_cond, t_dir, byte_block + t_length
184 // cdb[3]: features (7:0)
185 // cdb[4]: sector_count (7:0)
186 // cdb[5]: lba_low (7:0)
187 // cdb[6]: lba_mid (7:0)
188 // cdb[7]: lba_high (7:0)
190 // cdb[9]: (ata) command
192 // cdb[11]: control (SCSI, leave as zero)
195 // ATA Return Descriptor (component of descriptor sense data)
196 // des[0]: descriptor code (0x9)
197 // des[1]: additional descriptor length (0xc)
198 // des[2]: extend (bit 0)
200 // des[4]: sector_count (15:8)
201 // des[5]: sector_count (7:0)
202 // des[6]: lba_low (15:8)
203 // des[7]: lba_low (7:0)
204 // des[8]: lba_mid (15:8)
205 // des[9]: lba_mid (7:0)
206 // des[10]: lba_high (15:8)
207 // des[11]: lba_high (7:0)
214 // This interface routine takes ATA SMART commands and packages
215 // them in the SAT-defined ATA PASS THROUGH SCSI commands. There are
216 // two available SCSI commands: a 12 byte and 16 byte variant; the
217 // one used is chosen via this->m_passthrulen .
218 // DETAILED DESCRIPTION OF ARGUMENTS
219 // device: is the file descriptor provided by (a SCSI dvice type) open()
220 // command: defines the different ATA operations.
221 // select: additional input data if needed (which log, which type of
223 // data: location to write output data, if needed (512 bytes).
224 // Note: not all commands use all arguments.
226 // -1 if the command failed
227 // 0 if the command succeeded,
228 // STATUS_CHECK routine:
229 // -1 if the command failed
230 // 0 if the command succeeded and disk SMART status is "OK"
231 // 1 if the command succeeded and disk SMART status is "FAILING"
233 bool sat_device::ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
)
235 if (!ata_cmd_is_ok(in
,
236 true, // data_out_support
237 true, // multi_sector_support
238 true) // ata_48bit_support
242 struct scsi_cmnd_io io_hdr
;
243 struct scsi_sense_disect sinfo
;
244 struct sg_scsi_sense_hdr ssh
;
245 unsigned char cdb
[SAT_ATA_PASSTHROUGH_16LEN
];
246 unsigned char sense
[32];
247 const unsigned char * ardp
;
248 int status
, ard_len
, have_sense
;
250 int ck_cond
= 0; /* set to 1 to read register(s) back */
251 int protocol
= 3; /* non-data */
252 int t_dir
= 1; /* 0 -> to device, 1 -> from device */
253 int byte_block
= 1; /* 0 -> bytes, 1 -> 512 byte blocks */
254 int t_length
= 0; /* 0 -> no data transferred */
255 int passthru_size
= DEF_SAT_ATA_PASSTHRU_SIZE
;
257 memset(cdb
, 0, sizeof(cdb
));
258 memset(sense
, 0, sizeof(sense
));
260 // Set data direction
261 // TODO: This works only for commands where sector_count holds count!
262 switch (in
.direction
) {
263 case ata_cmd_in::no_data
:
265 case ata_cmd_in::data_in
:
266 protocol
= 4; // PIO data-in
267 t_length
= 2; // sector_count holds count
269 case ata_cmd_in::data_out
:
270 protocol
= 5; // PIO data-out
271 t_length
= 2; // sector_count holds count
272 t_dir
= 0; // to device
275 return set_err(EINVAL
, "sat_device::ata_pass_through: invalid direction=%d",
279 // Check condition if any output register needed
280 if (in
.out_needed
.is_set())
283 if ((SAT_ATA_PASSTHROUGH_12LEN
== m_passthrulen
) ||
284 (SAT_ATA_PASSTHROUGH_16LEN
== m_passthrulen
))
285 passthru_size
= m_passthrulen
;
287 // Set extend bit on 48-bit ATA command
288 if (in
.in_regs
.is_48bit_cmd()) {
289 if (passthru_size
!= SAT_ATA_PASSTHROUGH_16LEN
)
290 return set_err(ENOSYS
, "48-bit ATA commands require SAT ATA PASS-THROUGH (16)");
294 cdb
[0] = (SAT_ATA_PASSTHROUGH_12LEN
== passthru_size
) ?
295 SAT_ATA_PASSTHROUGH_12
: SAT_ATA_PASSTHROUGH_16
;
297 cdb
[1] = (protocol
<< 1) | extend
;
298 cdb
[2] = (ck_cond
<< 5) | (t_dir
<< 3) |
299 (byte_block
<< 2) | t_length
;
301 if (passthru_size
== SAT_ATA_PASSTHROUGH_12LEN
) {
302 // ATA PASS-THROUGH (12)
303 const ata_in_regs
& lo
= in
.in_regs
;
304 cdb
[3] = lo
.features
;
305 cdb
[4] = lo
.sector_count
;
308 cdb
[7] = lo
.lba_high
;
313 // ATA PASS-THROUGH (16)
314 const ata_in_regs
& lo
= in
.in_regs
;
315 const ata_in_regs
& hi
= in
.in_regs
.prev
;
316 // Note: all 'in.in_regs.prev.*' are always zero for 28-bit commands
317 cdb
[ 3] = hi
.features
;
318 cdb
[ 4] = lo
.features
;
319 cdb
[ 5] = hi
.sector_count
;
320 cdb
[ 6] = lo
.sector_count
;
321 cdb
[ 7] = hi
.lba_low
;
322 cdb
[ 8] = lo
.lba_low
;
323 cdb
[ 9] = hi
.lba_mid
;
324 cdb
[10] = lo
.lba_mid
;
325 cdb
[11] = hi
.lba_high
;
326 cdb
[12] = lo
.lba_high
;
328 cdb
[14] = lo
.command
;
331 memset(&io_hdr
, 0, sizeof(io_hdr
));
333 io_hdr
.dxfer_dir
= DXFER_NONE
;
334 io_hdr
.dxfer_len
= 0;
335 } else if (t_dir
) { /* from device */
336 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
337 io_hdr
.dxfer_len
= in
.size
;
338 io_hdr
.dxferp
= (unsigned char *)in
.buffer
;
339 memset(in
.buffer
, 0, in
.size
); // prefill with zeroes
340 } else { /* to device */
341 io_hdr
.dxfer_dir
= DXFER_TO_DEVICE
;
342 io_hdr
.dxfer_len
= in
.size
;
343 io_hdr
.dxferp
= (unsigned char *)in
.buffer
;
346 io_hdr
.cmnd_len
= passthru_size
;
347 io_hdr
.sensep
= sense
;
348 io_hdr
.max_sense_len
= sizeof(sense
);
349 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
351 scsi_device
* scsidev
= get_tunnel_dev();
352 if (!scsidev
->scsi_pass_through(&io_hdr
)) {
353 if (scsi_debugmode
> 0)
354 pout("sat_device::ata_pass_through: scsi_pass_through() failed, "
355 "errno=%d [%s]\n", scsidev
->get_errno(), scsidev
->get_errmsg());
356 return set_err(scsidev
->get_err());
360 have_sense
= sg_scsi_normalize_sense(io_hdr
.sensep
, io_hdr
.resp_sense_len
,
363 /* look for SAT ATA Return Descriptor */
364 ardp
= sg_scsi_sense_desc_find(io_hdr
.sensep
,
365 io_hdr
.resp_sense_len
,
366 ATA_RETURN_DESCRIPTOR
);
368 ard_len
= ardp
[1] + 2;
371 else if (ard_len
> 14)
374 scsi_do_sense_disect(&io_hdr
, &sinfo
);
375 status
= scsiSimpleSenseFilter(&sinfo
);
377 if (scsi_debugmode
> 0) {
378 pout("sat_device::ata_pass_through: scsi error: %s\n",
379 scsiErrString(status
));
380 if (ardp
&& (scsi_debugmode
> 1)) {
381 pout("Values from ATA Return Descriptor are:\n");
382 dStrHex((const char *)ardp
, ard_len
, 1);
385 if (t_dir
&& (t_length
> 0) && (in
.direction
== ata_cmd_in::data_in
))
386 memset(in
.buffer
, 0, in
.size
);
387 return set_err(EIO
, "scsi error %s", scsiErrString(status
));
390 if (ck_cond
) { /* expecting SAT specific sense data */
393 if (scsi_debugmode
> 1) {
394 pout("Values from ATA Return Descriptor are:\n");
395 dStrHex((const char *)ardp
, ard_len
, 1);
397 // Set output registers
398 ata_out_regs
& lo
= out
.out_regs
;
400 lo
.sector_count
= ardp
[ 5];
401 lo
.lba_low
= ardp
[ 7];
402 lo
.lba_mid
= ardp
[ 9];
403 lo
.lba_high
= ardp
[11];
404 lo
.device
= ardp
[12];
405 lo
.status
= ardp
[13];
406 if (in
.in_regs
.is_48bit_cmd()) {
407 ata_out_regs
& hi
= out
.out_regs
.prev
;
408 hi
.sector_count
= ardp
[ 4];
409 hi
.lba_low
= ardp
[ 6];
410 hi
.lba_mid
= ardp
[ 8];
411 hi
.lba_high
= ardp
[10];
416 ck_cond
= 0; /* not the type of sense data expected */
420 if ((ssh
.response_code
>= 0x72) &&
421 ((SCSI_SK_NO_SENSE
== ssh
.sense_key
) ||
422 (SCSI_SK_RECOVERED_ERR
== ssh
.sense_key
)) &&
424 (SCSI_ASCQ_ATA_PASS_THROUGH
== ssh
.ascq
)) {
426 if (scsi_debugmode
> 0) {
427 pout("Values from ATA Return Descriptor are:\n");
428 dStrHex((const char *)ardp
, ard_len
, 1);
430 return set_err(EIO
, "SAT command failed");
438 bool sat_device::scsi_pass_through(scsi_cmnd_io
* iop
)
440 scsi_device
* scsidev
= get_tunnel_dev();
441 if (!scsidev
->scsi_pass_through(iop
)) {
442 set_err(scsidev
->get_err());
448 smart_device
* sat_device::autodetect_open()
450 if (!open() || !m_enable_auto
)
453 scsi_device
* scsidev
= get_tunnel_dev();
455 unsigned char inqdata
[36] = {0, };
456 if (scsiStdInquiry(scsidev
, inqdata
, sizeof(inqdata
))) {
457 smart_device::error_info err
= scsidev
->get_err();
459 set_err(err
.no
, "INQUIRY [SAT]: %s", err
.msg
.c_str());
463 // Check for SAT "VENDOR"
464 int inqsize
= inqdata
[4] + 5;
465 bool sat
= (inqsize
>= 36 && !memcmp(inqdata
+ 8, "ATA ", 8));
471 set_info().dev_type
= (sat
? "sat" : scsidev
->get_dev_type());
472 set_info().info_name
= strprintf("%s [%s]", scsidev
->get_info_name(),
473 (sat
? "SAT" : "SCSI"));
479 /////////////////////////////////////////////////////////////////////////////
481 /* Attempt an IDENTIFY DEVICE ATA command via SATL when packet_interface
482 is false otherwise attempt IDENTIFY PACKET DEVICE. If successful
483 return true, else false */
485 static bool has_sat_pass_through(ata_device
* dev
, bool packet_interface
= false)
487 /* Note: malloc() ensures the read buffer lands on a single
488 page. This avoids some bugs seen on LSI controlers under
490 char *data
= (char *)malloc(512);
492 in
.in_regs
.command
= (packet_interface
? ATA_IDENTIFY_PACKET_DEVICE
: ATA_IDENTIFY_DEVICE
);
493 in
.set_data_in(data
, 1);
494 bool ret
= dev
->ata_pass_through(in
);
499 /////////////////////////////////////////////////////////////////////////////
501 /* Next two functions are borrowed from sg_lib.c in the sg3_utils
502 package. Same copyrght owner, same license as this file. */
503 static int sg_scsi_normalize_sense(const unsigned char * sensep
, int sb_len
,
504 struct sg_scsi_sense_hdr
* sshp
)
507 memset(sshp
, 0, sizeof(struct sg_scsi_sense_hdr
));
508 if ((NULL
== sensep
) || (0 == sb_len
) || (0x70 != (0x70 & sensep
[0])))
511 sshp
->response_code
= (0x7f & sensep
[0]);
512 if (sshp
->response_code
>= 0x72) { /* descriptor format */
514 sshp
->sense_key
= (0xf & sensep
[1]);
516 sshp
->asc
= sensep
[2];
518 sshp
->ascq
= sensep
[3];
520 sshp
->additional_length
= sensep
[7];
521 } else { /* fixed format */
523 sshp
->sense_key
= (0xf & sensep
[2]);
525 sb_len
= (sb_len
< (sensep
[7] + 8)) ? sb_len
:
528 sshp
->asc
= sensep
[12];
530 sshp
->ascq
= sensep
[13];
538 static const unsigned char * sg_scsi_sense_desc_find(const unsigned char * sensep
,
539 int sense_len
, int desc_type
)
541 int add_sen_len
, add_len
, desc_len
, k
;
542 const unsigned char * descp
;
544 if ((sense_len
< 8) || (0 == (add_sen_len
= sensep
[7])))
546 if ((sensep
[0] < 0x72) || (sensep
[0] > 0x73))
548 add_sen_len
= (add_sen_len
< (sense_len
- 8)) ?
549 add_sen_len
: (sense_len
- 8);
551 for (desc_len
= 0, k
= 0; k
< add_sen_len
; k
+= desc_len
) {
553 add_len
= (k
< (add_sen_len
- 1)) ? descp
[1]: -1;
554 desc_len
= add_len
+ 2;
555 if (descp
[0] == desc_type
)
557 if (add_len
< 0) /* short descriptor ?? */
564 // Call scsi_pass_through and check sense.
565 // TODO: Provide as member function of class scsi_device (?)
566 static bool scsi_pass_through_and_check(scsi_device
* scsidev
, scsi_cmnd_io
* iop
,
567 const char * msg
= "")
569 // Provide sense buffer
570 unsigned char sense
[32] = {0, };
572 iop
->max_sense_len
= sizeof(sense
);
573 iop
->timeout
= SCSI_TIMEOUT_DEFAULT
;
576 if (!scsidev
->scsi_pass_through(iop
)) {
577 if (scsi_debugmode
> 0)
578 pout("%sscsi_pass_through() failed, errno=%d [%s]\n",
579 msg
, scsidev
->get_errno(), scsidev
->get_errmsg());
584 scsi_sense_disect sinfo
;
585 scsi_do_sense_disect(iop
, &sinfo
);
586 int err
= scsiSimpleSenseFilter(&sinfo
);
588 if (scsi_debugmode
> 0)
589 pout("%sscsi error: %s\n", msg
, scsiErrString(err
));
590 return scsidev
->set_err(EIO
, "scsi error %s", scsiErrString(err
));
597 /////////////////////////////////////////////////////////////////////////////
601 /// Cypress USB Brigde support.
603 class usbcypress_device
604 : public tunnelled_device
<
605 /*implements*/ ata_device_with_command_set
606 /*by tunnelling through a*/, scsi_device
610 usbcypress_device(smart_interface
* intf
, scsi_device
* scsidev
,
611 const char * req_type
, unsigned char signature
);
613 virtual ~usbcypress_device() throw();
616 virtual int ata_command_interface(smart_command_set command
, int select
, char * data
);
618 unsigned char m_signature
;
622 usbcypress_device::usbcypress_device(smart_interface
* intf
, scsi_device
* scsidev
,
623 const char * req_type
, unsigned char signature
)
624 : smart_device(intf
, scsidev
->get_dev_name(), "sat", req_type
),
625 tunnelled_device
<ata_device_with_command_set
, scsi_device
>(scsidev
),
626 m_signature(signature
)
628 set_info().info_name
= strprintf("%s [USB Cypress]", scsidev
->get_info_name());
631 usbcypress_device::~usbcypress_device() throw()
636 /* see cy7c68300c_8.pdf for more information */
637 #define USBCYPRESS_PASSTHROUGH_LEN 16
638 int usbcypress_device::ata_command_interface(smart_command_set command
, int select
, char *data
)
640 struct scsi_cmnd_io io_hdr
;
641 unsigned char cdb
[USBCYPRESS_PASSTHROUGH_LEN
];
642 unsigned char sense
[32];
645 int ck_cond
= 0; /* set to 1 to read register(s) back */
646 int t_dir
= 1; /* 0 -> to device, 1 -> from device */
647 int byte_block
= 1; /* 0 -> bytes, 1 -> 512 byte blocks */
648 int t_length
= 0; /* 0 -> no data transferred */
651 int sector_count
= 0;
655 int passthru_size
= USBCYPRESS_PASSTHROUGH_LEN
;
657 memset(cdb
, 0, sizeof(cdb
));
658 memset(sense
, 0, sizeof(sense
));
660 ata_command
= ATA_SMART_CMD
;
662 case CHECK_POWER_MODE
:
663 ata_command
= ATA_CHECK_POWER_MODE
;
667 case READ_VALUES
: /* READ DATA */
668 feature
= ATA_SMART_READ_VALUES
;
669 sector_count
= 1; /* one (512 byte) block */
670 t_length
= 2; /* sector count holds count */
673 case READ_THRESHOLDS
: /* obsolete */
674 feature
= ATA_SMART_READ_THRESHOLDS
;
675 sector_count
= 1; /* one (512 byte) block */
677 t_length
= 2; /* sector count holds count */
681 feature
= ATA_SMART_READ_LOG_SECTOR
;
682 sector_count
= 1; /* one (512 byte) block */
684 t_length
= 2; /* sector count holds count */
688 feature
= ATA_SMART_WRITE_LOG_SECTOR
;
689 sector_count
= 1; /* one (512 byte) block */
691 t_length
= 2; /* sector count holds count */
692 t_dir
= 0; /* to device */
696 ata_command
= ATA_IDENTIFY_DEVICE
;
697 sector_count
= 1; /* one (512 byte) block */
698 t_length
= 2; /* sector count holds count */
702 ata_command
= ATA_IDENTIFY_PACKET_DEVICE
;
703 sector_count
= 1; /* one (512 byte) block */
704 t_length
= 2; /* sector count (7:0) holds count */
708 feature
= ATA_SMART_ENABLE
;
712 feature
= ATA_SMART_DISABLE
;
716 // this command only says if SMART is working. It could be
717 // replaced with STATUS_CHECK below.
718 feature
= ATA_SMART_STATUS
;
722 feature
= ATA_SMART_AUTO_OFFLINE
;
723 sector_count
= select
; // YET NOTE - THIS IS A NON-DATA COMMAND!!
726 feature
= ATA_SMART_AUTOSAVE
;
727 sector_count
= select
; // YET NOTE - THIS IS A NON-DATA COMMAND!!
729 case IMMEDIATE_OFFLINE
:
730 feature
= ATA_SMART_IMMEDIATE_OFFLINE
;
734 // This command uses HDIO_DRIVE_TASK and has different syntax than
735 // the other commands.
736 feature
= ATA_SMART_STATUS
; /* SMART RETURN STATUS */
740 pout("Unrecognized command %d in usbcypress_device::ata_command_interface()\n"
741 "Please contact " PACKAGE_BUGREPORT
"\n", command
);
745 if (ATA_SMART_CMD
== ata_command
) {
750 cdb
[0] = m_signature
; // bVSCBSignature : vendor-specific command
751 cdb
[1] = 0x24; // bVSCBSubCommand : 0x24 for ATACB
753 if (ata_command
== ATA_IDENTIFY_DEVICE
|| ata_command
== ATA_IDENTIFY_PACKET_DEVICE
)
754 cdb
[2] |= (1<<7); //set IdentifyPacketDevice for these cmds
755 cdb
[3] = 0xff - (1<<0) - (1<<6); //features, sector count, lba low, lba med
756 // lba high, command are valid
757 cdb
[4] = byte_block
; //TransferBlockCount : 512
761 cdb
[7] = sector_count
;
765 cdb
[12] = ata_command
;
767 memset(&io_hdr
, 0, sizeof(io_hdr
));
769 io_hdr
.dxfer_dir
= DXFER_NONE
;
770 io_hdr
.dxfer_len
= 0;
771 } else if (t_dir
) { /* from device */
772 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
773 io_hdr
.dxfer_len
= copydata
;
774 io_hdr
.dxferp
= (unsigned char *)data
;
775 memset(data
, 0, copydata
); /* prefill with zeroes */
776 } else { /* to device */
777 io_hdr
.dxfer_dir
= DXFER_TO_DEVICE
;
778 io_hdr
.dxfer_len
= outlen
;
779 io_hdr
.dxferp
= (unsigned char *)data
;
782 io_hdr
.cmnd_len
= passthru_size
;
783 io_hdr
.sensep
= sense
;
784 io_hdr
.max_sense_len
= sizeof(sense
);
785 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
787 scsi_device
* scsidev
= get_tunnel_dev();
788 if (!scsidev
->scsi_pass_through(&io_hdr
)) {
789 if (scsi_debugmode
> 0)
790 pout("usbcypress_device::ata_command_interface: scsi_pass_through() failed, "
791 "errno=%d [%s]\n", scsidev
->get_errno(), scsidev
->get_errmsg());
792 set_err(scsidev
->get_err());
796 // if there is a sense the command failed or the
797 // device doesn't support usbcypress
798 if (io_hdr
.scsi_status
== SCSI_STATUS_CHECK_CONDITION
&&
799 sg_scsi_normalize_sense(io_hdr
.sensep
, io_hdr
.resp_sense_len
, NULL
)) {
803 unsigned char ardp
[8];
805 /* XXX this is racy if there other scsi command between
806 * the first usbcypress command and this one
808 //pout("If you got strange result, please retry without traffic on the disc\n");
809 /* we use the same command as before, but we set
810 * * the read taskfile bit, for not executing usbcypress command,
811 * * but reading register selected in srb->cmnd[4]
813 cdb
[2] = (1<<0); /* ask read taskfile */
814 memset(sense
, 0, sizeof(sense
));
816 /* transfert 8 bytes */
817 memset(&io_hdr
, 0, sizeof(io_hdr
));
818 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
819 io_hdr
.dxfer_len
= ard_len
;
820 io_hdr
.dxferp
= (unsigned char *)ardp
;
821 memset(ardp
, 0, ard_len
); /* prefill with zeroes */
824 io_hdr
.cmnd_len
= passthru_size
;
825 io_hdr
.sensep
= sense
;
826 io_hdr
.max_sense_len
= sizeof(sense
);
827 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
830 if (!scsidev
->scsi_pass_through(&io_hdr
)) {
831 if (scsi_debugmode
> 0)
832 pout("usbcypress_device::ata_command_interface: scsi_pass_through() failed, "
833 "errno=%d [%s]\n", scsidev
->get_errno(), scsidev
->get_errmsg());
834 set_err(scsidev
->get_err());
837 // if there is a sense the command failed or the
838 // device doesn't support usbcypress
839 if (io_hdr
.scsi_status
== SCSI_STATUS_CHECK_CONDITION
&&
840 sg_scsi_normalize_sense(io_hdr
.sensep
, io_hdr
.resp_sense_len
, NULL
)) {
845 if (scsi_debugmode
> 1) {
846 pout("Values from ATA Return Descriptor are:\n");
847 dStrHex((const char *)ardp
, ard_len
, 1);
850 if (ATA_CHECK_POWER_MODE
== ata_command
)
851 data
[0] = ardp
[2]; /* sector count (0:7) */
852 else if (STATUS_CHECK
== command
) {
853 if ((ardp
[4] == 0x4f) && (ardp
[5] == 0xc2))
854 return 0; /* GOOD smart status */
855 if ((ardp
[4] == 0xf4) && (ardp
[5] == 0x2c))
856 return 1; // smart predicting failure, "bad" status
857 // We haven't gotten output that makes sense so
858 // print out some debugging info
859 syserror("Error SMART Status command failed");
860 pout("This may be due to a race in usbcypress\n");
861 pout("Retry without other disc access\n");
862 pout("Please get assistance from " PACKAGE_HOMEPAGE
"\n");
863 pout("Values from ATA Return Descriptor are:\n");
864 dStrHex((const char *)ardp
, ard_len
, 1);
871 #if 0 // Not used, see autodetect_sat_device() below.
872 static int isprint_string(const char *s
)
875 if (isprint(*s
) == 0)
882 /* Attempt an IDENTIFY DEVICE ATA or IDENTIFY PACKET DEVICE command
883 If successful return 1, else 0 */
884 // TODO: Combine with has_sat_pass_through above
885 static int has_usbcypress_pass_through(ata_device
* atadev
, const char *manufacturer
, const char *product
)
887 struct ata_identify_device drive
;
888 char model
[40], serial
[20], firm
[8];
890 /* issue the command and do a checksum if possible */
891 if (ataReadHDIdentity(atadev
, &drive
) < 0)
894 /* check if model string match, revision doesn't work for me */
895 format_ata_string(model
, drive
.model
, 40);
896 if (*model
== 0 || isprint_string(model
) == 0)
899 if (manufacturer
&& strncmp(manufacturer
, model
, 8))
900 pout("manufacturer doesn't match in pass_through test\n");
902 strlen(model
) > 8 && strncmp(product
, model
+8, strlen(model
)-8))
903 pout("product doesn't match in pass_through test\n");
906 format_ata_string(serial
, drive
.serial_no
, 20);
907 if (isprint_string(serial
) == 0)
909 format_ata_string(firm
, drive
.fw_rev
, 8);
910 if (isprint_string(firm
) == 0)
916 /////////////////////////////////////////////////////////////////////////////
918 /// JMicron USB Bridge support.
920 class usbjmicron_device
921 : public tunnelled_device
<
922 /*implements*/ ata_device
,
923 /*by tunnelling through a*/ scsi_device
927 usbjmicron_device(smart_interface
* intf
, scsi_device
* scsidev
,
928 const char * req_type
, bool ata_48bit_support
, int port
);
930 virtual ~usbjmicron_device() throw();
934 virtual bool ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
);
937 bool get_registers(unsigned short addr
, unsigned char * buf
, unsigned short size
);
939 bool m_ata_48bit_support
;
944 usbjmicron_device::usbjmicron_device(smart_interface
* intf
, scsi_device
* scsidev
,
945 const char * req_type
, bool ata_48bit_support
, int port
)
946 : smart_device(intf
, scsidev
->get_dev_name(), "usbjmicron", req_type
),
947 tunnelled_device
<ata_device
, scsi_device
>(scsidev
),
948 m_ata_48bit_support(ata_48bit_support
), m_port(port
)
950 set_info().info_name
= strprintf("%s [USB JMicron]", scsidev
->get_info_name());
953 usbjmicron_device::~usbjmicron_device() throw()
958 bool usbjmicron_device::open()
961 if (!tunnelled_device
<ata_device
, scsi_device
>::open())
964 // Detect port if not specified
966 unsigned char regbuf
[1] = {0};
967 if (!get_registers(0x720f, regbuf
, sizeof(regbuf
))) {
972 switch (regbuf
[0] & 0x44) {
979 return set_err(EINVAL
, "Two devices connected, try '-d usbjmicron,[01]'");
982 return set_err(ENODEV
, "No device connected");
990 bool usbjmicron_device::ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
)
992 if (!ata_cmd_is_ok(in
,
993 true, // data_out_support
994 false, // !multi_sector_support
995 m_ata_48bit_support
) // limited, see below
999 bool is_smart_status
= ( in
.in_regs
.command
== ATA_SMART_CMD
1000 && in
.in_regs
.features
== ATA_SMART_STATUS
);
1002 // Support output registers for SMART STATUS
1003 if (in
.out_needed
.is_set() && !is_smart_status
)
1004 return set_err(ENOSYS
, "ATA output registers not supported");
1006 // Support 48-bit commands with zero high bytes
1007 if (in
.in_regs
.is_real_48bit_cmd())
1008 return set_err(ENOSYS
, "48-bit ATA commands not fully supported");
1011 return set_err(EIO
, "Unknown JMicron port");
1013 scsi_cmnd_io io_hdr
;
1014 memset(&io_hdr
, 0, sizeof(io_hdr
));
1017 unsigned char smart_status
= 0;
1019 if (is_smart_status
&& in
.out_needed
.is_set()) {
1020 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
1021 io_hdr
.dxfer_len
= 1;
1022 io_hdr
.dxferp
= &smart_status
;
1024 else switch (in
.direction
) {
1025 case ata_cmd_in::no_data
:
1026 io_hdr
.dxfer_dir
= DXFER_NONE
;
1028 case ata_cmd_in::data_in
:
1029 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
1030 io_hdr
.dxfer_len
= in
.size
;
1031 io_hdr
.dxferp
= (unsigned char *)in
.buffer
;
1032 memset(in
.buffer
, 0, in
.size
);
1034 case ata_cmd_in::data_out
:
1035 io_hdr
.dxfer_dir
= DXFER_TO_DEVICE
;
1036 io_hdr
.dxfer_len
= in
.size
;
1037 io_hdr
.dxferp
= (unsigned char *)in
.buffer
;
1041 return set_err(EINVAL
);
1044 // Build pass through command
1045 unsigned char cdb
[12];
1047 cdb
[ 1] = (rwbit
? 0x10 : 0x00);
1049 cdb
[ 3] = (unsigned char)(io_hdr
.dxfer_len
>> 8);
1050 cdb
[ 4] = (unsigned char)(io_hdr
.dxfer_len
);
1051 cdb
[ 5] = in
.in_regs
.features
;
1052 cdb
[ 6] = in
.in_regs
.sector_count
;
1053 cdb
[ 7] = in
.in_regs
.lba_low
;
1054 cdb
[ 8] = in
.in_regs
.lba_mid
;
1055 cdb
[ 9] = in
.in_regs
.lba_high
;
1056 cdb
[10] = in
.in_regs
.device
| (m_port
== 0 ? 0xa0 : 0xb0);
1057 cdb
[11] = in
.in_regs
.command
;
1060 io_hdr
.cmnd_len
= sizeof(cdb
);
1062 scsi_device
* scsidev
= get_tunnel_dev();
1063 if (!scsi_pass_through_and_check(scsidev
, &io_hdr
,
1064 "usbjmicron_device::ata_pass_through: "))
1065 return set_err(scsidev
->get_err());
1067 if (in
.out_needed
.is_set()) {
1068 if (is_smart_status
) {
1069 switch (smart_status
) {
1070 case 0x01: case 0xc2:
1071 out
.out_regs
.lba_high
= 0xc2;
1072 out
.out_regs
.lba_mid
= 0x4f;
1074 case 0x00: case 0x2c:
1075 out
.out_regs
.lba_high
= 0x2c;
1076 out
.out_regs
.lba_mid
= 0xf4;
1081 #if 0 // Not needed for SMART STATUS, see also notes below
1083 // Read ATA output registers
1084 // NOTE: The register addresses are not valid for some older chip revisions
1085 // NOTE: There is a small race condition here!
1086 unsigned char regbuf
[16] = {0, };
1087 if (!get_registers((m_port
== 0 ? 0x8000 : 0x9000), regbuf
, sizeof(regbuf
)))
1090 out
.out_regs
.sector_count
= regbuf
[ 0];
1091 out
.out_regs
.lba_mid
= regbuf
[ 4];
1092 out
.out_regs
.lba_low
= regbuf
[ 6];
1093 out
.out_regs
.device
= regbuf
[ 9];
1094 out
.out_regs
.lba_high
= regbuf
[10];
1095 out
.out_regs
.error
= regbuf
[13];
1096 out
.out_regs
.status
= regbuf
[14];
1104 bool usbjmicron_device::get_registers(unsigned short addr
,
1105 unsigned char * buf
, unsigned short size
)
1107 unsigned char cdb
[12];
1111 cdb
[ 3] = (unsigned char)(size
>> 8);
1112 cdb
[ 4] = (unsigned char)(size
);
1114 cdb
[ 6] = (unsigned char)(addr
>> 8);
1115 cdb
[ 7] = (unsigned char)(addr
);
1121 scsi_cmnd_io io_hdr
;
1122 memset(&io_hdr
, 0, sizeof(io_hdr
));
1123 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
1124 io_hdr
.dxfer_len
= size
;
1125 io_hdr
.dxferp
= buf
;
1127 io_hdr
.cmnd_len
= sizeof(cdb
);
1129 scsi_device
* scsidev
= get_tunnel_dev();
1130 if (!scsi_pass_through_and_check(scsidev
, &io_hdr
,
1131 "usbjmicron_device::get_registers: "))
1132 return set_err(scsidev
->get_err());
1138 /////////////////////////////////////////////////////////////////////////////
1140 /// SunplusIT USB Bridge support.
1142 class usbsunplus_device
1143 : public tunnelled_device
<
1144 /*implements*/ ata_device
,
1145 /*by tunnelling through a*/ scsi_device
1149 usbsunplus_device(smart_interface
* intf
, scsi_device
* scsidev
,
1150 const char * req_type
);
1152 virtual ~usbsunplus_device() throw();
1154 virtual bool ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
);
1158 usbsunplus_device::usbsunplus_device(smart_interface
* intf
, scsi_device
* scsidev
,
1159 const char * req_type
)
1160 : smart_device(intf
, scsidev
->get_dev_name(), "usbsunplus", req_type
),
1161 tunnelled_device
<ata_device
, scsi_device
>(scsidev
)
1163 set_info().info_name
= strprintf("%s [USB Sunplus]", scsidev
->get_info_name());
1166 usbsunplus_device::~usbsunplus_device() throw()
1170 bool usbsunplus_device::ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
)
1172 if (!ata_cmd_is_ok(in
,
1173 true, // data_out_support
1174 false, // !multi_sector_support
1175 true) // ata_48bit_support
1179 scsi_cmnd_io io_hdr
;
1180 unsigned char cdb
[12];
1182 if (in
.in_regs
.is_48bit_cmd()) {
1183 // Set "previous" registers
1184 memset(&io_hdr
, 0, sizeof(io_hdr
));
1185 io_hdr
.dxfer_dir
= DXFER_NONE
;
1189 cdb
[ 2] = 0x23; // Subcommand: Pass through presetting
1192 cdb
[ 5] = in
.in_regs
.prev
.features
;
1193 cdb
[ 6] = in
.in_regs
.prev
.sector_count
;
1194 cdb
[ 7] = in
.in_regs
.prev
.lba_low
;
1195 cdb
[ 8] = in
.in_regs
.prev
.lba_mid
;
1196 cdb
[ 9] = in
.in_regs
.prev
.lba_high
;
1201 io_hdr
.cmnd_len
= sizeof(cdb
);
1203 scsi_device
* scsidev
= get_tunnel_dev();
1204 if (!scsi_pass_through_and_check(scsidev
, &io_hdr
,
1205 "usbsunplus_device::scsi_pass_through (presetting): "))
1206 return set_err(scsidev
->get_err());
1209 // Run Pass through command
1210 memset(&io_hdr
, 0, sizeof(io_hdr
));
1211 unsigned char protocol
;
1212 switch (in
.direction
) {
1213 case ata_cmd_in::no_data
:
1214 io_hdr
.dxfer_dir
= DXFER_NONE
;
1217 case ata_cmd_in::data_in
:
1218 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
1219 io_hdr
.dxfer_len
= in
.size
;
1220 io_hdr
.dxferp
= (unsigned char *)in
.buffer
;
1221 memset(in
.buffer
, 0, in
.size
);
1224 case ata_cmd_in::data_out
:
1225 io_hdr
.dxfer_dir
= DXFER_TO_DEVICE
;
1226 io_hdr
.dxfer_len
= in
.size
;
1227 io_hdr
.dxferp
= (unsigned char *)in
.buffer
;
1231 return set_err(EINVAL
);
1236 cdb
[ 2] = 0x22; // Subcommand: Pass through
1238 cdb
[ 4] = (unsigned char)(io_hdr
.dxfer_len
>> 9);
1239 cdb
[ 5] = in
.in_regs
.features
;
1240 cdb
[ 6] = in
.in_regs
.sector_count
;
1241 cdb
[ 7] = in
.in_regs
.lba_low
;
1242 cdb
[ 8] = in
.in_regs
.lba_mid
;
1243 cdb
[ 9] = in
.in_regs
.lba_high
;
1244 cdb
[10] = in
.in_regs
.device
| 0xa0;
1245 cdb
[11] = in
.in_regs
.command
;
1248 io_hdr
.cmnd_len
= sizeof(cdb
);
1250 scsi_device
* scsidev
= get_tunnel_dev();
1251 if (!scsi_pass_through_and_check(scsidev
, &io_hdr
,
1252 "usbsunplus_device::scsi_pass_through: "))
1253 // Returns sense key 0x03 (medium error) on ATA command error
1254 return set_err(scsidev
->get_err());
1256 if (in
.out_needed
.is_set()) {
1257 // Read ATA output registers
1258 unsigned char regbuf
[8] = {0, };
1259 memset(&io_hdr
, 0, sizeof(io_hdr
));
1260 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
1261 io_hdr
.dxfer_len
= sizeof(regbuf
);
1262 io_hdr
.dxferp
= regbuf
;
1266 cdb
[ 2] = 0x21; // Subcommand: Get status
1267 memset(cdb
+3, 0, sizeof(cdb
)-3);
1269 io_hdr
.cmnd_len
= sizeof(cdb
);
1271 if (!scsi_pass_through_and_check(scsidev
, &io_hdr
,
1272 "usbsunplus_device::scsi_pass_through (get registers): "))
1273 return set_err(scsidev
->get_err());
1275 out
.out_regs
.error
= regbuf
[1];
1276 out
.out_regs
.sector_count
= regbuf
[2];
1277 out
.out_regs
.lba_low
= regbuf
[3];
1278 out
.out_regs
.lba_mid
= regbuf
[4];
1279 out
.out_regs
.lba_high
= regbuf
[5];
1280 out
.out_regs
.device
= regbuf
[6];
1281 out
.out_regs
.status
= regbuf
[7];
1290 using namespace sat
;
1293 /////////////////////////////////////////////////////////////////////////////
1295 // Return ATA->SCSI filter for SAT or USB.
1297 ata_device
* smart_interface::get_sat_device(const char * type
, scsi_device
* scsidev
)
1299 if (!strncmp(type
, "sat", 3)) {
1300 const char * t
= type
+ 3;
1301 bool enable_auto
= false;
1302 if (!strncmp(t
, ",auto", 5)) {
1306 int ptlen
= 0, n
= -1;
1307 if (*t
&& !(sscanf(t
, ",%d%n", &ptlen
, &n
) == 1 && n
== (int)strlen(t
)
1308 && (ptlen
== 0 || ptlen
== 12 || ptlen
== 16))) {
1309 set_err(EINVAL
, "Option '-d sat[,auto][,N]' requires N to be 0, 12 or 16");
1312 return new sat_device(this, scsidev
, type
, ptlen
, enable_auto
);
1315 else if (!strncmp(type
, "usbcypress", 10)) {
1316 unsigned signature
= 0x24; int n1
= -1, n2
= -1;
1317 if (!(((sscanf(type
, "usbcypress%n,0x%x%n", &n1
, &signature
, &n2
) == 1 && n2
== (int)strlen(type
)) || n1
== (int)strlen(type
))
1318 && signature
<= 0xff)) {
1319 set_err(EINVAL
, "Option '-d usbcypress,<n>' requires <n> to be "
1320 "an hexadecimal number between 0x0 and 0xff");
1323 return new usbcypress_device(this, scsidev
, type
, signature
);
1326 else if (!strncmp(type
, "usbjmicron", 10)) {
1327 const char * t
= type
+ 10;
1328 bool ata_48bit_support
= false;
1329 if (!strncmp(t
, ",x", 2)) {
1331 ata_48bit_support
= true;
1333 int port
= -1, n
= -1;
1334 if (*t
&& !( (sscanf(t
, ",%d%n", &port
, &n
) == 1
1335 && n
== (int)strlen(t
) && 0 <= port
&& port
<= 1))) {
1336 set_err(EINVAL
, "Option '-d usbmicron[,x],<n>' requires <n> to be 0 or 1");
1339 return new usbjmicron_device(this, scsidev
, type
, ata_48bit_support
, port
);
1342 else if (!strcmp(type
, "usbsunplus")) {
1343 return new usbsunplus_device(this, scsidev
, type
);
1347 set_err(EINVAL
, "Unknown USB device type '%s'", type
);
1352 // Try to detect a SAT device behind a SCSI interface.
1354 ata_device
* smart_interface::autodetect_sat_device(scsi_device
* scsidev
,
1355 const unsigned char * inqdata
, unsigned inqsize
)
1357 if (!scsidev
->is_open())
1361 if (inqdata
&& inqsize
>= 36 && !memcmp(inqdata
+ 8, "ATA ", 8)) { // TODO: Linux-specific?
1362 ata_device_auto_ptr
atadev( new sat_device(this, scsidev
, "") , scsidev
);
1363 if (has_sat_pass_through(atadev
.get()))
1364 return atadev
.release(); // Detected SAT
1371 /////////////////////////////////////////////////////////////////////////////
1372 // USB device type detection
1374 // Format USB ID for error messages
1375 static std::string
format_usb_id(int vendor_id
, int product_id
, int version
)
1378 return strprintf("[0x%04x:0x%04x (0x%03x)]", vendor_id
, product_id
, version
);
1380 return strprintf("[0x%04x:0x%04x]", vendor_id
, product_id
);
1383 // Get type name for USB device with known VENDOR:PRODUCT ID.
1384 const char * smart_interface::get_usb_dev_type_by_id(int vendor_id
, int product_id
,
1385 int version
/*= -1*/)
1387 usb_dev_info info
, info2
;
1388 int n
= lookup_usb_device(vendor_id
, product_id
, version
, info
, info2
);
1391 set_err(EINVAL
, "Unknown USB bridge %s",
1392 format_usb_id(vendor_id
, product_id
, version
).c_str());
1397 set_err(EINVAL
, "USB bridge %s type is ambiguous: '%s' or '%s'",
1398 format_usb_id(vendor_id
, product_id
, version
).c_str(),
1399 (!info
.usb_type
.empty() ? info
.usb_type
.c_str() : "[unsupported]"),
1400 (!info2
.usb_type
.empty() ? info2
.usb_type
.c_str() : "[unsupported]"));
1404 if (info
.usb_type
.empty()) {
1405 set_err(ENOSYS
, "Unsupported USB bridge %s",
1406 format_usb_id(vendor_id
, product_id
, version
).c_str());
1410 // TODO: change return type to std::string
1411 static std::string type
;
1412 type
= info
.usb_type
;
1413 return type
.c_str();