root/trunk/sm5/scsiata.cpp @ 2655

Revision 2655, 28.9 KB (checked in by chrfranke, 6 years ago)

Add '-d sat+TYPE' to use SAT with controllers which require '-d TYPE'.

Line 
1/*
2 * scsiata.cpp
3 *
4 * Home page of code is: http://smartmontools.sourceforge.net
5 *
6 * Copyright (C) 2006-8 Douglas Gilbert <dougg@torque.net>
7 *
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, or (at your option)
11 * any later version.
12 *
13 * You should have received a copy of the GNU General Public License
14 * (for example COPYING); if not, write to the Free
15 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 *
17 * The code in this file is based on the SCSI to ATA Translation (SAT)
18 * draft found at http://www.t10.org . The original draft used for this
19 * code is sat-r08.pdf which is not too far away from becoming a
20 * standard. The SAT commands of interest to smartmontools are the
21 * ATA PASS THROUGH SCSI (16) and ATA PASS THROUGH SCSI (12) defined in
22 * section 12 of that document.
23 *
24 * With more transports "hiding" SATA disks (and other S-ATAPI devices)
25 * behind a SCSI command set, accessing special features like SMART
26 * information becomes a challenge. The SAT standard offers ATA PASS
27 * THROUGH commands for special usages. Note that the SAT layer may
28 * be inside a generic OS layer (e.g. libata in linux), in a host
29 * adapter (HA or HBA) firmware, or somewhere on the interconnect
30 * between the host computer and the SATA devices (e.g. a RAID made
31 * of SATA disks and the RAID talks "SCSI" to the host computer).
32 * Note that in the latter case, this code does not solve the
33 * addressing issue (i.e. which SATA disk to address behind the logical
34 * SCSI (RAID) interface).
35 *
36 */
37
38#include <stdio.h>
39#include <string.h>
40#include <ctype.h>
41
42#include "config.h"
43#include "int64.h"
44#include "extern.h"
45#include "scsicmds.h"
46#include "scsiata.h"
47#include "atacmds.h" // ataReadHDIdentity()
48#include "utility.h"
49#include "dev_interface.h"
50#include "dev_ata_cmd_set.h" // ata_device_with_command_set
51#include "dev_tunnelled.h" // tunnelled_device<>
52
53const char *scsiata_c_cvsid="$Id: scsiata.cpp,v 1.19 2008/09/29 19:13:49 chrfranke Exp $"
54CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID SCSIATA_H_CVSID UTILITY_H_CVSID;
55
56/* for passing global control variables */
57extern smartmonctrl *con;
58
59#define DEF_SAT_ATA_PASSTHRU_SIZE 16
60#define ATA_RETURN_DESCRIPTOR 9
61
62namespace sat { // no need to publish anything, name provided for Doxygen
63
64/// SAT support.
65/// Implements ATA by tunnelling through SCSI.
66
67class sat_device
68: public tunnelled_device<
69    /*implements*/ ata_device
70    /*by tunnelling through a*/, scsi_device
71  >
72{
73public:
74  sat_device(smart_interface * intf, scsi_device * scsidev,
75    const char * req_type, int passthrulen = 0);
76
77  virtual ~sat_device() throw();
78
79  virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
80
81private:
82  int m_passthrulen;
83};
84
85
86sat_device::sat_device(smart_interface * intf, scsi_device * scsidev,
87  const char * req_type, int passthrulen /*= 0*/)
88: smart_device(intf, scsidev->get_dev_name(), "sat", req_type),
89  tunnelled_device<ata_device, scsi_device>(scsidev),
90  m_passthrulen(passthrulen)
91{
92  set_info().info_name = strprintf("%s [SAT]", scsidev->get_info_name());
93}
94
95sat_device::~sat_device() throw()
96{
97}
98
99
100// cdb[0]: ATA PASS THROUGH (16) SCSI command opcode byte (0x85)
101// cdb[1]: multiple_count, protocol + extend
102// cdb[2]: offline, ck_cond, t_dir, byte_block + t_length
103// cdb[3]: features (15:8)
104// cdb[4]: features (7:0)
105// cdb[5]: sector_count (15:8)
106// cdb[6]: sector_count (7:0)
107// cdb[7]: lba_low (15:8)
108// cdb[8]: lba_low (7:0)
109// cdb[9]: lba_mid (15:8)
110// cdb[10]: lba_mid (7:0)
111// cdb[11]: lba_high (15:8)
112// cdb[12]: lba_high (7:0)
113// cdb[13]: device
114// cdb[14]: (ata) command
115// cdb[15]: control (SCSI, leave as zero)
116//
117// 24 bit lba (from MSB): cdb[12] cdb[10] cdb[8]
118// 48 bit lba (from MSB): cdb[11] cdb[9] cdb[7] cdb[12] cdb[10] cdb[8]
119//
120//
121// cdb[0]: ATA PASS THROUGH (12) SCSI command opcode byte (0xa1)
122// cdb[1]: multiple_count, protocol + extend
123// cdb[2]: offline, ck_cond, t_dir, byte_block + t_length
124// cdb[3]: features (7:0)
125// cdb[4]: sector_count (7:0)
126// cdb[5]: lba_low (7:0)
127// cdb[6]: lba_mid (7:0)
128// cdb[7]: lba_high (7:0)
129// cdb[8]: device
130// cdb[9]: (ata) command
131// cdb[10]: reserved
132// cdb[11]: control (SCSI, leave as zero)
133//
134//
135// ATA Return Descriptor (component of descriptor sense data)
136// des[0]: descriptor code (0x9)
137// des[1]: additional descriptor length (0xc)
138// des[2]: extend (bit 0)
139// des[3]: error
140// des[4]: sector_count (15:8)
141// des[5]: sector_count (7:0)
142// des[6]: lba_low (15:8)
143// des[7]: lba_low (7:0)
144// des[8]: lba_mid (15:8)
145// des[9]: lba_mid (7:0)
146// des[10]: lba_high (15:8)
147// des[11]: lba_high (7:0)
148// des[12]: device
149// des[13]: status
150
151
152
153// PURPOSE
154//   This interface routine takes ATA SMART commands and packages
155//   them in the SAT-defined ATA PASS THROUGH SCSI commands. There are
156//   two available SCSI commands: a 12 byte and 16 byte variant; the
157//   one used is chosen via this->m_passthrulen .
158// DETAILED DESCRIPTION OF ARGUMENTS
159//   device: is the file descriptor provided by (a SCSI dvice type) open()
160//   command: defines the different ATA operations.
161//   select: additional input data if needed (which log, which type of
162//           self-test).
163//   data:   location to write output data, if needed (512 bytes).
164//     Note: not all commands use all arguments.
165// RETURN VALUES
166//  -1 if the command failed
167//   0 if the command succeeded,
168//   STATUS_CHECK routine:
169//  -1 if the command failed
170//   0 if the command succeeded and disk SMART status is "OK"
171//   1 if the command succeeded and disk SMART status is "FAILING"
172
173bool sat_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
174{
175  if (!ata_cmd_is_ok(in,
176    true, // data_out_support
177    true, // multi_sector_support
178    true) // ata_48bit_support
179  )
180    return false;
181
182    struct scsi_cmnd_io io_hdr;
183    struct scsi_sense_disect sinfo;
184    struct sg_scsi_sense_hdr ssh;
185    unsigned char cdb[SAT_ATA_PASSTHROUGH_16LEN];
186    unsigned char sense[32];
187    const unsigned char * ardp;
188    int status, ard_len, have_sense;
189    int extend = 0;
190    int ck_cond = 0;    /* set to 1 to read register(s) back */
191    int protocol = 3;   /* non-data */
192    int t_dir = 1;      /* 0 -> to device, 1 -> from device */
193    int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */
194    int t_length = 0;   /* 0 -> no data transferred */
195    int passthru_size = DEF_SAT_ATA_PASSTHRU_SIZE;
196
197    memset(cdb, 0, sizeof(cdb));
198    memset(sense, 0, sizeof(sense));
199
200    // Set data direction
201    // TODO: This works only for commands where sector_count holds count!
202    switch (in.direction) {
203      case ata_cmd_in::no_data:
204        break;
205      case ata_cmd_in::data_in:
206        protocol = 4;  // PIO data-in
207        t_length = 2;  // sector_count holds count
208        break;
209      case ata_cmd_in::data_out:
210        protocol = 5;  // PIO data-out
211        t_length = 2;  // sector_count holds count
212        t_dir = 0;     // to device
213        break;
214      default:
215        return set_err(EINVAL, "sat_device::ata_pass_through: invalid direction=%d",
216            (int)in.direction);
217    }
218
219    // Check condition if any output register needed
220    if (in.out_needed.is_set())
221        ck_cond = 1;
222
223    if ((SAT_ATA_PASSTHROUGH_12LEN == m_passthrulen) ||
224        (SAT_ATA_PASSTHROUGH_16LEN == m_passthrulen))
225        passthru_size = m_passthrulen;
226
227    // Set extend bit on 48-bit ATA command
228    if (in.in_regs.is_48bit_cmd()) {
229      if (passthru_size != SAT_ATA_PASSTHROUGH_16LEN)
230        return set_err(ENOSYS, "48-bit ATA commands require SAT ATA PASS-THROUGH (16)");
231      extend = 1;
232    }
233
234    cdb[0] = (SAT_ATA_PASSTHROUGH_12LEN == passthru_size) ?
235             SAT_ATA_PASSTHROUGH_12 : SAT_ATA_PASSTHROUGH_16;
236
237    cdb[1] = (protocol << 1) | extend;
238    cdb[2] = (ck_cond << 5) | (t_dir << 3) |
239             (byte_block << 2) | t_length;
240
241    if (passthru_size == SAT_ATA_PASSTHROUGH_12LEN) {
242        // ATA PASS-THROUGH (12)
243        const ata_in_regs & lo = in.in_regs;
244        cdb[3] = lo.features;
245        cdb[4] = lo.sector_count;
246        cdb[5] = lo.lba_low;
247        cdb[6] = lo.lba_mid;
248        cdb[7] = lo.lba_high;
249        cdb[8] = lo.device;
250        cdb[9] = lo.command;
251    }
252    else {
253        // ATA PASS-THROUGH (16)
254        const ata_in_regs & lo = in.in_regs;
255        const ata_in_regs & hi = in.in_regs.prev;
256        // Note: all 'in.in_regs.prev.*' are always zero for 28-bit commands
257        cdb[ 3] = hi.features;
258        cdb[ 4] = lo.features;
259        cdb[ 5] = hi.sector_count;
260        cdb[ 6] = lo.sector_count;
261        cdb[ 7] = hi.lba_low;
262        cdb[ 8] = lo.lba_low;
263        cdb[ 9] = hi.lba_mid;
264        cdb[10] = lo.lba_mid;
265        cdb[11] = hi.lba_high;
266        cdb[12] = lo.lba_high;
267        cdb[13] = lo.device;
268        cdb[14] = lo.command;
269    }
270
271    memset(&io_hdr, 0, sizeof(io_hdr));
272    if (0 == t_length) {
273        io_hdr.dxfer_dir = DXFER_NONE;
274        io_hdr.dxfer_len = 0;
275    } else if (t_dir) {         /* from device */
276        io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
277        io_hdr.dxfer_len = in.size;
278        io_hdr.dxferp = (unsigned char *)in.buffer;
279        memset(in.buffer, 0, in.size); // prefill with zeroes
280    } else {                    /* to device */
281        io_hdr.dxfer_dir = DXFER_TO_DEVICE;
282        io_hdr.dxfer_len = in.size;
283        io_hdr.dxferp = (unsigned char *)in.buffer;
284    }
285    io_hdr.cmnd = cdb;
286    io_hdr.cmnd_len = passthru_size;
287    io_hdr.sensep = sense;
288    io_hdr.max_sense_len = sizeof(sense);
289    io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
290
291    scsi_device * scsidev = get_tunnel_dev();
292    if (!scsidev->scsi_pass_through(&io_hdr)) {
293        if (con->reportscsiioctl > 0)
294            pout("sat_device::ata_pass_through: scsi_pass_through() failed, "
295                 "errno=%d [%s]\n", scsidev->get_errno(), scsidev->get_errmsg());
296        return set_err(scsidev->get_err());
297    }
298    ardp = NULL;
299    ard_len = 0;
300    have_sense = sg_scsi_normalize_sense(io_hdr.sensep, io_hdr.resp_sense_len,
301                                         &ssh);
302    if (have_sense) {
303        /* look for SAT ATA Return Descriptor */
304        ardp = sg_scsi_sense_desc_find(io_hdr.sensep,
305                                       io_hdr.resp_sense_len,
306                                       ATA_RETURN_DESCRIPTOR);
307        if (ardp) {
308            ard_len = ardp[1] + 2;
309            if (ard_len < 12)
310                ard_len = 12;
311            else if (ard_len > 14)
312                ard_len = 14;
313        }
314        scsi_do_sense_disect(&io_hdr, &sinfo);
315        status = scsiSimpleSenseFilter(&sinfo);
316        if (0 != status) {
317            if (con->reportscsiioctl > 0) {
318                pout("sat_device::ata_pass_through: scsi error: %s\n",
319                     scsiErrString(status));
320                if (ardp && (con->reportscsiioctl > 1)) {
321                    pout("Values from ATA Return Descriptor are:\n");
322                    dStrHex((const char *)ardp, ard_len, 1);
323                }
324            }
325            if (t_dir && (t_length > 0) && (in.direction == ata_cmd_in::data_in))
326                memset(in.buffer, 0, in.size);
327            return set_err(EIO, "scsi error %s", scsiErrString(status));
328        }
329    }
330    if (ck_cond) {     /* expecting SAT specific sense data */
331        if (have_sense) {
332            if (ardp) {
333                if (con->reportscsiioctl > 1) {
334                    pout("Values from ATA Return Descriptor are:\n");
335                    dStrHex((const char *)ardp, ard_len, 1);
336                }
337                // Set output registers
338                ata_out_regs & lo = out.out_regs;
339                lo.error        = ardp[ 3];
340                lo.sector_count = ardp[ 5];
341                lo.lba_low      = ardp[ 7];
342                lo.lba_mid      = ardp[ 9];
343                lo.lba_high     = ardp[11];
344                lo.device       = ardp[12];
345                lo.status       = ardp[13];
346                if (in.in_regs.is_48bit_cmd()) {
347                    ata_out_regs & hi = out.out_regs.prev;
348                    hi.sector_count = ardp[ 4];
349                    hi.lba_low      = ardp[ 6];
350                    hi.lba_mid      = ardp[ 8];
351                    hi.lba_high     = ardp[10];
352                }
353            }
354        }
355        if (ardp == NULL)
356            ck_cond = 0;       /* not the type of sense data expected */
357    }
358    if (0 == ck_cond) {
359        if (have_sense) {
360            if ((ssh.response_code >= 0x72) &&
361                ((SCSI_SK_NO_SENSE == ssh.sense_key) ||
362                 (SCSI_SK_RECOVERED_ERR == ssh.sense_key)) &&
363                (0 == ssh.asc) &&
364                (SCSI_ASCQ_ATA_PASS_THROUGH == ssh.ascq)) {
365                if (ardp) {
366                    if (con->reportscsiioctl > 0) {
367                        pout("Values from ATA Return Descriptor are:\n");
368                        dStrHex((const char *)ardp, ard_len, 1);
369                    }
370                    return set_err(EIO, "SAT command failed");
371                }
372            }
373        }
374    }
375    return true;
376}
377
378} // namespace
379
380/////////////////////////////////////////////////////////////////////////////
381
382/* Attempt an IDENTIFY DEVICE ATA command via SATL when packet_interface
383   is false otherwise attempt IDENTIFY PACKET DEVICE. If successful
384   return true, else false */
385
386static bool has_sat_pass_through(ata_device * dev, bool packet_interface = false)
387{
388    ata_cmd_in in;
389    in.in_regs.command = (packet_interface ? ATA_IDENTIFY_PACKET_DEVICE : ATA_IDENTIFY_DEVICE);
390    char data[512];
391    in.set_data_in(data, 1);
392    return dev->ata_pass_through(in);
393}
394
395/////////////////////////////////////////////////////////////////////////////
396
397/* Next two functions are borrowed from sg_lib.c in the sg3_utils
398   package. Same copyrght owner, same license as this file. */
399int sg_scsi_normalize_sense(const unsigned char * sensep, int sb_len,
400                            struct sg_scsi_sense_hdr * sshp)
401{
402    if (sshp)
403        memset(sshp, 0, sizeof(struct sg_scsi_sense_hdr));
404    if ((NULL == sensep) || (0 == sb_len) || (0x70 != (0x70 & sensep[0])))
405        return 0;
406    if (sshp) {
407        sshp->response_code = (0x7f & sensep[0]);
408        if (sshp->response_code >= 0x72) {  /* descriptor format */
409            if (sb_len > 1)
410                sshp->sense_key = (0xf & sensep[1]);
411            if (sb_len > 2)
412                sshp->asc = sensep[2];
413            if (sb_len > 3)
414                sshp->ascq = sensep[3];
415            if (sb_len > 7)
416                sshp->additional_length = sensep[7];
417        } else {                              /* fixed format */
418            if (sb_len > 2)
419                sshp->sense_key = (0xf & sensep[2]);
420            if (sb_len > 7) {
421                sb_len = (sb_len < (sensep[7] + 8)) ? sb_len :
422                                                      (sensep[7] + 8);
423                if (sb_len > 12)
424                    sshp->asc = sensep[12];
425                if (sb_len > 13)
426                    sshp->ascq = sensep[13];
427            }
428        }
429    }
430    return 1;
431}
432
433
434const unsigned char * sg_scsi_sense_desc_find(const unsigned char * sensep,
435                                              int sense_len, int desc_type)
436{
437    int add_sen_len, add_len, desc_len, k;
438    const unsigned char * descp;
439
440    if ((sense_len < 8) || (0 == (add_sen_len = sensep[7])))
441        return NULL;
442    if ((sensep[0] < 0x72) || (sensep[0] > 0x73))
443        return NULL;
444    add_sen_len = (add_sen_len < (sense_len - 8)) ?
445                         add_sen_len : (sense_len - 8);
446    descp = &sensep[8];
447    for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
448        descp += desc_len;
449        add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
450        desc_len = add_len + 2;
451        if (descp[0] == desc_type)
452            return descp;
453        if (add_len < 0) /* short descriptor ?? */
454            break;
455    }
456    return NULL;
457}
458
459
460/////////////////////////////////////////////////////////////////////////////
461
462namespace sat {
463
464/// Cypress USB Brigde support.
465
466class usbcypress_device
467: public tunnelled_device<
468    /*implements*/ ata_device_with_command_set
469    /*by tunnelling through a*/, scsi_device
470  >
471{
472public:
473  usbcypress_device(smart_interface * intf, scsi_device * scsidev,
474    const char * req_type, unsigned char signature);
475
476  virtual ~usbcypress_device() throw();
477
478protected:
479  virtual int ata_command_interface(smart_command_set command, int select, char * data);
480
481  unsigned char m_signature;
482};
483
484
485usbcypress_device::usbcypress_device(smart_interface * intf, scsi_device * scsidev,
486  const char * req_type, unsigned char signature)
487: smart_device(intf, scsidev->get_dev_name(), "sat", req_type),
488  tunnelled_device<ata_device_with_command_set, scsi_device>(scsidev),
489  m_signature(signature)
490{
491  set_info().info_name = strprintf("%s [USB Cypress]", scsidev->get_info_name());
492}
493
494usbcypress_device::~usbcypress_device() throw()
495{
496}
497
498
499/* see cy7c68300c_8.pdf for more information */
500#define USBCYPRESS_PASSTHROUGH_LEN 16
501int usbcypress_device::ata_command_interface(smart_command_set command, int select, char *data)
502{
503    struct scsi_cmnd_io io_hdr;
504    unsigned char cdb[USBCYPRESS_PASSTHROUGH_LEN];
505    unsigned char sense[32];
506    int copydata = 0;
507    int outlen = 0;
508    int ck_cond = 0;    /* set to 1 to read register(s) back */
509    int protocol = 3;   /* non-data */
510    int t_dir = 1;      /* 0 -> to device, 1 -> from device */
511    int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */
512    int t_length = 0;   /* 0 -> no data transferred */
513    int feature = 0;
514    int ata_command = 0;
515    int sector_count = 0;
516    int lba_low = 0;
517    int lba_mid = 0;
518    int lba_high = 0;
519    int passthru_size = USBCYPRESS_PASSTHROUGH_LEN;
520
521    memset(cdb, 0, sizeof(cdb));
522    memset(sense, 0, sizeof(sense));
523
524    ata_command = ATA_SMART_CMD;
525    switch (command) {
526    case CHECK_POWER_MODE:
527        ata_command = ATA_CHECK_POWER_MODE;
528        ck_cond = 1;
529        copydata = 1;
530        break;
531    case READ_VALUES:           /* READ DATA */
532        feature = ATA_SMART_READ_VALUES;
533        sector_count = 1;     /* one (512 byte) block */
534        protocol = 4;   /* PIO data-in */
535        t_length = 2;   /* sector count holds count */
536        copydata = 512;
537        break;
538    case READ_THRESHOLDS:       /* obsolete */
539        feature = ATA_SMART_READ_THRESHOLDS;
540        sector_count = 1;     /* one (512 byte) block */
541        lba_low = 1;
542        protocol = 4;   /* PIO data-in */
543        t_length = 2;   /* sector count holds count */
544        copydata=512;
545        break;
546    case READ_LOG:
547        feature = ATA_SMART_READ_LOG_SECTOR;
548        sector_count = 1;     /* one (512 byte) block */
549        lba_low = select;
550        protocol = 4;   /* PIO data-in */
551        t_length = 2;   /* sector count holds count */
552        copydata = 512;
553        break;
554    case WRITE_LOG:
555        feature = ATA_SMART_WRITE_LOG_SECTOR;
556        sector_count = 1;     /* one (512 byte) block */
557        lba_low = select;
558        protocol = 5;   /* PIO data-out */
559        t_length = 2;   /* sector count holds count */
560        t_dir = 0;      /* to device */
561        outlen = 512;
562        break;
563    case IDENTIFY:
564        ata_command = ATA_IDENTIFY_DEVICE;
565        sector_count = 1;     /* one (512 byte) block */
566        protocol = 4;   /* PIO data-in */
567        t_length = 2;   /* sector count holds count */
568        copydata = 512;
569        break;
570    case PIDENTIFY:
571        ata_command = ATA_IDENTIFY_PACKET_DEVICE;
572        sector_count = 1;     /* one (512 byte) block */
573        protocol = 4;   /* PIO data-in */
574        t_length = 2;   /* sector count (7:0) holds count */
575        copydata = 512;
576        break;
577    case ENABLE:
578        feature = ATA_SMART_ENABLE;
579        lba_low = 1;
580        break;
581    case DISABLE:
582        feature = ATA_SMART_DISABLE;
583        lba_low = 1;
584        break;
585    case STATUS:
586        // this command only says if SMART is working.  It could be
587        // replaced with STATUS_CHECK below.
588        feature = ATA_SMART_STATUS;
589        ck_cond = 1;
590        break;
591    case AUTO_OFFLINE:
592        feature = ATA_SMART_AUTO_OFFLINE;
593        sector_count = select;   // YET NOTE - THIS IS A NON-DATA COMMAND!!
594        break;
595    case AUTOSAVE:
596        feature = ATA_SMART_AUTOSAVE;
597        sector_count = select;   // YET NOTE - THIS IS A NON-DATA COMMAND!!
598        break;
599    case IMMEDIATE_OFFLINE:
600        feature = ATA_SMART_IMMEDIATE_OFFLINE;
601        lba_low = select;
602        break;
603    case STATUS_CHECK:
604        // This command uses HDIO_DRIVE_TASK and has different syntax than
605        // the other commands.
606        feature = ATA_SMART_STATUS;      /* SMART RETURN STATUS */
607        ck_cond = 1;
608        break;
609    default:
610        pout("Unrecognized command %d in usbcypress_device::ata_command_interface()\n"
611             "Please contact " PACKAGE_BUGREPORT "\n", command);
612        errno=ENOSYS;
613        return -1;
614    }
615    if (ATA_SMART_CMD == ata_command) {
616        lba_mid = 0x4f;
617        lba_high = 0xc2;
618    }
619
620    cdb[0] = m_signature; // bVSCBSignature : vendor-specific command
621    cdb[1] = 0x24; // bVSCBSubCommand : 0x24 for ATACB
622    cdb[2] = 0x0;
623    if (ata_command == ATA_IDENTIFY_DEVICE || ata_command == ATA_IDENTIFY_PACKET_DEVICE)
624        cdb[2] |= (1<<7); //set  IdentifyPacketDevice for these cmds
625    cdb[3] = 0xff - (1<<0) - (1<<6); //features, sector count, lba low, lba med
626                                     // lba high, command are valid
627    cdb[4] = byte_block; //TransferBlockCount : 512
628
629
630    cdb[6] = feature;
631    cdb[7] = sector_count;
632    cdb[8] = lba_low;
633    cdb[9] = lba_mid;
634    cdb[10] = lba_high;
635    cdb[12] = ata_command;
636
637    memset(&io_hdr, 0, sizeof(io_hdr));
638    if (0 == t_length) {
639        io_hdr.dxfer_dir = DXFER_NONE;
640        io_hdr.dxfer_len = 0;
641    } else if (t_dir) {         /* from device */
642        io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
643        io_hdr.dxfer_len = copydata;
644        io_hdr.dxferp = (unsigned char *)data;
645        memset(data, 0, copydata); /* prefill with zeroes */
646    } else {                    /* to device */
647        io_hdr.dxfer_dir = DXFER_TO_DEVICE;
648        io_hdr.dxfer_len = outlen;
649        io_hdr.dxferp = (unsigned char *)data;
650    }
651    io_hdr.cmnd = cdb;
652    io_hdr.cmnd_len = passthru_size;
653    io_hdr.sensep = sense;
654    io_hdr.max_sense_len = sizeof(sense);
655    io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
656
657    scsi_device * scsidev = get_tunnel_dev();
658    if (!scsidev->scsi_pass_through(&io_hdr)) {
659        if (con->reportscsiioctl > 0)
660            pout("usbcypress_device::ata_command_interface: scsi_pass_through() failed, "
661                 "errno=%d [%s]\n", scsidev->get_errno(), scsidev->get_errmsg());
662        set_err(scsidev->get_err());
663        return -1;
664    }
665
666    // if there is a sense the command failed or the
667    // device doesn't support usbcypress
668    if (io_hdr.scsi_status == SCSI_STATUS_CHECK_CONDITION && 
669            sg_scsi_normalize_sense(io_hdr.sensep, io_hdr.resp_sense_len, NULL)) {
670        return -1;
671    }
672    if (ck_cond) {
673        unsigned char ardp[8];
674        int ard_len = 8;
675        /* XXX this is racy if there other scsi command between
676         * the first usbcypress command and this one
677         */
678        //pout("If you got strange result, please retry without traffic on the disc\n");
679        /* we use the same command as before, but we set
680         * * the read taskfile bit, for not executing usbcypress command,
681         * * but reading register selected in srb->cmnd[4]
682         */
683        cdb[2] = (1<<0); /* ask read taskfile */
684        memset(sense, 0, sizeof(sense));
685
686        /* transfert 8 bytes */
687        memset(&io_hdr, 0, sizeof(io_hdr));
688        io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
689        io_hdr.dxfer_len = ard_len;
690        io_hdr.dxferp = (unsigned char *)ardp;
691        memset(ardp, 0, ard_len); /* prefill with zeroes */
692
693        io_hdr.cmnd = cdb;
694        io_hdr.cmnd_len = passthru_size;
695        io_hdr.sensep = sense;
696        io_hdr.max_sense_len = sizeof(sense);
697        io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
698
699
700        if (!scsidev->scsi_pass_through(&io_hdr)) {
701            if (con->reportscsiioctl > 0)
702                pout("usbcypress_device::ata_command_interface: scsi_pass_through() failed, "
703                     "errno=%d [%s]\n", scsidev->get_errno(), scsidev->get_errmsg());
704            set_err(scsidev->get_err());
705            return -1;
706        }
707        // if there is a sense the command failed or the
708        // device doesn't support usbcypress
709        if (io_hdr.scsi_status == SCSI_STATUS_CHECK_CONDITION && 
710                sg_scsi_normalize_sense(io_hdr.sensep, io_hdr.resp_sense_len, NULL)) {
711            return -1;
712        }
713
714
715        if (con->reportscsiioctl > 1) {
716            pout("Values from ATA Return Descriptor are:\n");
717            dStrHex((const char *)ardp, ard_len, 1);
718        }
719
720        if (ATA_CHECK_POWER_MODE == ata_command)
721            data[0] = ardp[2];      /* sector count (0:7) */
722        else if (STATUS_CHECK == command) {
723            if ((ardp[4] == 0x4f) && (ardp[5] == 0xc2))
724                return 0;    /* GOOD smart status */
725            if ((ardp[4] == 0xf4) && (ardp[5] == 0x2c))
726                return 1;    // smart predicting failure, "bad" status
727            // We haven't gotten output that makes sense so
728            // print out some debugging info
729            syserror("Error SMART Status command failed");
730            pout("This may be due to a race in usbcypress\n");
731            pout("Retry without other disc access\n");
732            pout("Please get assistance from " PACKAGE_HOMEPAGE "\n");
733            pout("Values from ATA Return Descriptor are:\n");
734            dStrHex((const char *)ardp, ard_len, 1);
735            return -1;
736        }
737    }
738    return 0;
739}
740
741static int isprint_string(const char *s)
742{
743    while (*s) {
744        if (isprint(*s) == 0)
745            return 0;
746        s++;
747    }
748    return 1;
749}
750
751/* Attempt an IDENTIFY DEVICE ATA or IDENTIFY PACKET DEVICE command
752   If successful return 1, else 0 */
753// TODO: Combine with has_sat_pass_through above
754static int has_usbcypress_pass_through(ata_device * atadev, const char *manufacturer, const char *product)
755{
756    struct ata_identify_device drive;
757    char model[40], serial[20], firm[8];
758
759    /* issue the command and do a checksum if possible */
760    if (ataReadHDIdentity(atadev, &drive) < 0)
761        return 0;
762
763    /* check if model string match, revision doesn't work for me */
764    format_ata_string(model, drive.model, 40);
765    if (*model == 0 || isprint_string(model) == 0)
766        return 0;
767
768    if (manufacturer && strncmp(manufacturer, model, 8))
769        pout("manufacturer doesn't match in pass_through test\n");
770    if (product &&
771            strlen(model) > 8 && strncmp(product, model+8, strlen(model)-8))
772        pout("product doesn't match in pass_through test\n");
773
774    /* check serial */
775    format_ata_string(serial, drive.serial_no, 20);
776    if (isprint_string(serial) == 0)
777        return 0;
778    format_ata_string(firm, drive.fw_rev, 8);
779    if (isprint_string(firm) == 0)
780        return 0;
781    return 1;
782}
783
784} // namespace
785
786using namespace sat;
787
788
789/////////////////////////////////////////////////////////////////////////////
790
791// Return ATA->SCSI filter for SAT or USB.
792
793ata_device * smart_interface::get_sat_device(const char * type, scsi_device * scsidev)
794{
795  if (!strncmp(type, "sat", 3)) {
796    int ptlen = 0, n1 = -1, n2 = -1;
797    if (!(((sscanf(type, "sat%n,%d%n", &n1, &ptlen, &n2) == 1 && n2 == (int)strlen(type)) || n1 == (int)strlen(type))
798        && (ptlen == 0 || ptlen == 12 || ptlen == 16))) {
799      set_err(EINVAL, "Option '-d sat,<n>' requires <n> to be 0, 12 or 16");
800      return 0;
801    }
802    return new sat_device(this, scsidev, type, ptlen);
803  }
804  else if (!strncmp(type, "usbcypress", 10)) {
805    unsigned signature = 0x24; int n1 = -1, n2 = -1;
806    if (!(((sscanf(type, "usbcypress%n,0x%x%n", &n1, &signature, &n2) == 1 && n2 == (int)strlen(type)) || n1 == (int)strlen(type))
807          && signature <= 0xff)) {
808      set_err(EINVAL, "Option '-d usbcypress,<n>' requires <n> to be "
809                      "an hexadecimal number between 0x0 and 0xff");
810      return 0;
811    }
812    return new usbcypress_device(this, scsidev, type, signature);
813  }
814  else {
815    set_err(EINVAL, "Unknown USB device type '%s'", type);
816    return 0;
817  }
818}
819
820// Try to detect a SAT device behind a SCSI interface.
821
822ata_device * smart_interface::autodetect_sat_device(scsi_device * scsidev,
823  const unsigned char * inqdata, unsigned inqsize)
824{
825  if (!scsidev->is_open())
826    return 0;
827
828  ata_device * atadev = 0;
829  try {
830    // SAT ?
831    if (inqdata && inqsize >= 36 && !memcmp(inqdata + 8, "ATA     ", 8)) { // TODO: Linux-specific?
832      atadev = new sat_device(this, scsidev, "");
833      if (has_sat_pass_through(atadev))
834        return atadev; // Detected SAT
835      atadev->release(scsidev);
836      delete atadev;
837    }
838
839    // USB ?
840    {
841      atadev = new usbcypress_device(this, scsidev, "", 0x24);
842      if (has_usbcypress_pass_through(atadev,
843            (inqdata && inqsize >= 36 ? (const char*)inqdata  + 8 : 0),
844            (inqdata && inqsize >= 36 ? (const char*)inqdata + 16 : 0) ))
845        return atadev; // Detected USB
846      atadev->release(scsidev);
847      delete atadev;
848    }
849  }
850  catch (...) {
851    if (atadev) {
852      atadev->release(scsidev);
853      delete atadev;
854    }
855    throw;
856  }
857
858  return 0;
859}
Note: See TracBrowser for help on using the browser.