Annotation of embedaddon/smartmontools/scsiata.cpp, revision 1.1

1.1     ! misho       1: /*
        !             2:  * scsiata.cpp
        !             3:  *
        !             4:  * Home page of code is: http://smartmontools.sourceforge.net
        !             5:  *
        !             6:  * Copyright (C) 2006-10 Douglas Gilbert <dgilbert@interlog.com>
        !             7:  * Copyright (C) 2009-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
        !             8:  *
        !             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)
        !            12:  * any later version.
        !            13:  *
        !            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.
        !            17:  *
        !            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.
        !            24:  *
        !            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.
        !            34:  *
        !            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).
        !            46:  * 
        !            47:  */
        !            48: 
        !            49: #include <stdio.h>
        !            50: #include <string.h>
        !            51: #include <stdlib.h>
        !            52: #include <ctype.h>
        !            53: #include <errno.h>
        !            54: 
        !            55: #include "config.h"
        !            56: #include "int64.h"
        !            57: #include "scsicmds.h"
        !            58: #include "atacmds.h" // ataReadHDIdentity()
        !            59: #include "knowndrives.h" // lookup_usb_device()
        !            60: #include "utility.h"
        !            61: #include "dev_interface.h"
        !            62: #include "dev_ata_cmd_set.h" // ata_device_with_command_set
        !            63: #include "dev_tunnelled.h" // tunnelled_device<>
        !            64: 
        !            65: const char * scsiata_cpp_cvsid = "$Id: scsiata.cpp 3441 2011-10-12 17:22:15Z chrfranke $";
        !            66: 
        !            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;
        !            77:     unsigned char asc;
        !            78:     unsigned char ascq;
        !            79:     unsigned char byte4;
        !            80:     unsigned char byte5;
        !            81:     unsigned char byte6;
        !            82:     unsigned char additional_length;
        !            83: };
        !            84: 
        !            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);
        !            94: 
        !            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);
        !           100: 
        !           101: #define SAT_ATA_PASSTHROUGH_12LEN 12
        !           102: #define SAT_ATA_PASSTHROUGH_16LEN 16
        !           103: 
        !           104: #define DEF_SAT_ATA_PASSTHRU_SIZE 16
        !           105: #define ATA_RETURN_DESCRIPTOR 9
        !           106: 
        !           107: 
        !           108: namespace sat { // no need to publish anything, name provided for Doxygen
        !           109: 
        !           110: /// SAT support.
        !           111: /// Implements ATA by tunnelling through SCSI.
        !           112: 
        !           113: class sat_device
        !           114: : public tunnelled_device<
        !           115:     /*implements*/ ata_device
        !           116:     /*by tunnelling through a*/, scsi_device
        !           117:   >
        !           118: {
        !           119: public:
        !           120:   sat_device(smart_interface * intf, scsi_device * scsidev,
        !           121:     const char * req_type, int passthrulen = 0);
        !           122: 
        !           123:   virtual ~sat_device() throw();
        !           124: 
        !           125:   virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
        !           126: 
        !           127: private:
        !           128:   int m_passthrulen;
        !           129: };
        !           130: 
        !           131: 
        !           132: sat_device::sat_device(smart_interface * intf, scsi_device * scsidev,
        !           133:   const char * req_type, int passthrulen /*= 0*/)
        !           134: : smart_device(intf, scsidev->get_dev_name(), "sat", req_type),
        !           135:   tunnelled_device<ata_device, scsi_device>(scsidev),
        !           136:   m_passthrulen(passthrulen)
        !           137: {
        !           138:   set_info().info_name = strprintf("%s [SAT]", scsidev->get_info_name());
        !           139: }
        !           140: 
        !           141: sat_device::~sat_device() throw()
        !           142: {
        !           143: }
        !           144: 
        !           145: 
        !           146: // cdb[0]: ATA PASS THROUGH (16) SCSI command opcode byte (0x85)
        !           147: // cdb[1]: multiple_count, protocol + extend
        !           148: // cdb[2]: offline, ck_cond, t_dir, byte_block + t_length
        !           149: // cdb[3]: features (15:8)
        !           150: // cdb[4]: features (7:0)
        !           151: // cdb[5]: sector_count (15:8)
        !           152: // cdb[6]: sector_count (7:0)
        !           153: // cdb[7]: lba_low (15:8)
        !           154: // cdb[8]: lba_low (7:0)
        !           155: // cdb[9]: lba_mid (15:8)
        !           156: // cdb[10]: lba_mid (7:0)
        !           157: // cdb[11]: lba_high (15:8)
        !           158: // cdb[12]: lba_high (7:0)
        !           159: // cdb[13]: device
        !           160: // cdb[14]: (ata) command
        !           161: // cdb[15]: control (SCSI, leave as zero)
        !           162: //
        !           163: // 24 bit lba (from MSB): cdb[12] cdb[10] cdb[8]
        !           164: // 48 bit lba (from MSB): cdb[11] cdb[9] cdb[7] cdb[12] cdb[10] cdb[8]
        !           165: //
        !           166: //
        !           167: // cdb[0]: ATA PASS THROUGH (12) SCSI command opcode byte (0xa1)
        !           168: // cdb[1]: multiple_count, protocol + extend
        !           169: // cdb[2]: offline, ck_cond, t_dir, byte_block + t_length
        !           170: // cdb[3]: features (7:0)
        !           171: // cdb[4]: sector_count (7:0)
        !           172: // cdb[5]: lba_low (7:0)
        !           173: // cdb[6]: lba_mid (7:0)
        !           174: // cdb[7]: lba_high (7:0)
        !           175: // cdb[8]: device
        !           176: // cdb[9]: (ata) command
        !           177: // cdb[10]: reserved
        !           178: // cdb[11]: control (SCSI, leave as zero)
        !           179: //
        !           180: //
        !           181: // ATA Return Descriptor (component of descriptor sense data)
        !           182: // des[0]: descriptor code (0x9)
        !           183: // des[1]: additional descriptor length (0xc)
        !           184: // des[2]: extend (bit 0)
        !           185: // des[3]: error
        !           186: // des[4]: sector_count (15:8)
        !           187: // des[5]: sector_count (7:0)
        !           188: // des[6]: lba_low (15:8)
        !           189: // des[7]: lba_low (7:0)
        !           190: // des[8]: lba_mid (15:8)
        !           191: // des[9]: lba_mid (7:0)
        !           192: // des[10]: lba_high (15:8)
        !           193: // des[11]: lba_high (7:0)
        !           194: // des[12]: device
        !           195: // des[13]: status
        !           196: 
        !           197: 
        !           198: 
        !           199: // PURPOSE
        !           200: //   This interface routine takes ATA SMART commands and packages
        !           201: //   them in the SAT-defined ATA PASS THROUGH SCSI commands. There are
        !           202: //   two available SCSI commands: a 12 byte and 16 byte variant; the
        !           203: //   one used is chosen via this->m_passthrulen .
        !           204: // DETAILED DESCRIPTION OF ARGUMENTS
        !           205: //   device: is the file descriptor provided by (a SCSI dvice type) open()
        !           206: //   command: defines the different ATA operations.
        !           207: //   select: additional input data if needed (which log, which type of
        !           208: //           self-test).
        !           209: //   data:   location to write output data, if needed (512 bytes).
        !           210: //     Note: not all commands use all arguments.
        !           211: // RETURN VALUES
        !           212: //  -1 if the command failed
        !           213: //   0 if the command succeeded,
        !           214: //   STATUS_CHECK routine: 
        !           215: //  -1 if the command failed
        !           216: //   0 if the command succeeded and disk SMART status is "OK"
        !           217: //   1 if the command succeeded and disk SMART status is "FAILING"
        !           218: 
        !           219: bool sat_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
        !           220: {
        !           221:   if (!ata_cmd_is_ok(in,
        !           222:     true, // data_out_support
        !           223:     true, // multi_sector_support
        !           224:     true) // ata_48bit_support
        !           225:   )
        !           226:     return false;
        !           227: 
        !           228:     struct scsi_cmnd_io io_hdr;
        !           229:     struct scsi_sense_disect sinfo;
        !           230:     struct sg_scsi_sense_hdr ssh;
        !           231:     unsigned char cdb[SAT_ATA_PASSTHROUGH_16LEN];
        !           232:     unsigned char sense[32];
        !           233:     const unsigned char * ardp;
        !           234:     int status, ard_len, have_sense;
        !           235:     int extend = 0;
        !           236:     int ck_cond = 0;    /* set to 1 to read register(s) back */
        !           237:     int protocol = 3;   /* non-data */
        !           238:     int t_dir = 1;      /* 0 -> to device, 1 -> from device */
        !           239:     int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */
        !           240:     int t_length = 0;   /* 0 -> no data transferred */
        !           241:     int passthru_size = DEF_SAT_ATA_PASSTHRU_SIZE;
        !           242: 
        !           243:     memset(cdb, 0, sizeof(cdb));
        !           244:     memset(sense, 0, sizeof(sense));
        !           245: 
        !           246:     // Set data direction
        !           247:     // TODO: This works only for commands where sector_count holds count!
        !           248:     switch (in.direction) {
        !           249:       case ata_cmd_in::no_data:
        !           250:         break;
        !           251:       case ata_cmd_in::data_in:
        !           252:         protocol = 4;  // PIO data-in
        !           253:         t_length = 2;  // sector_count holds count
        !           254:         break;
        !           255:       case ata_cmd_in::data_out:
        !           256:         protocol = 5;  // PIO data-out
        !           257:         t_length = 2;  // sector_count holds count
        !           258:         t_dir = 0;     // to device
        !           259:         break;
        !           260:       default:
        !           261:         return set_err(EINVAL, "sat_device::ata_pass_through: invalid direction=%d",
        !           262:             (int)in.direction);
        !           263:     }
        !           264: 
        !           265:     // Check condition if any output register needed
        !           266:     if (in.out_needed.is_set())
        !           267:         ck_cond = 1;
        !           268: 
        !           269:     if ((SAT_ATA_PASSTHROUGH_12LEN == m_passthrulen) ||
        !           270:         (SAT_ATA_PASSTHROUGH_16LEN == m_passthrulen))
        !           271:         passthru_size = m_passthrulen;
        !           272: 
        !           273:     // Set extend bit on 48-bit ATA command
        !           274:     if (in.in_regs.is_48bit_cmd()) {
        !           275:       if (passthru_size != SAT_ATA_PASSTHROUGH_16LEN)
        !           276:         return set_err(ENOSYS, "48-bit ATA commands require SAT ATA PASS-THROUGH (16)");
        !           277:       extend = 1;
        !           278:     }
        !           279: 
        !           280:     cdb[0] = (SAT_ATA_PASSTHROUGH_12LEN == passthru_size) ?
        !           281:              SAT_ATA_PASSTHROUGH_12 : SAT_ATA_PASSTHROUGH_16;
        !           282: 
        !           283:     cdb[1] = (protocol << 1) | extend;
        !           284:     cdb[2] = (ck_cond << 5) | (t_dir << 3) |
        !           285:              (byte_block << 2) | t_length;
        !           286: 
        !           287:     if (passthru_size == SAT_ATA_PASSTHROUGH_12LEN) {
        !           288:         // ATA PASS-THROUGH (12)
        !           289:         const ata_in_regs & lo = in.in_regs;
        !           290:         cdb[3] = lo.features;
        !           291:         cdb[4] = lo.sector_count;
        !           292:         cdb[5] = lo.lba_low;
        !           293:         cdb[6] = lo.lba_mid;
        !           294:         cdb[7] = lo.lba_high;
        !           295:         cdb[8] = lo.device;
        !           296:         cdb[9] = lo.command;
        !           297:     }
        !           298:     else {
        !           299:         // ATA PASS-THROUGH (16)
        !           300:         const ata_in_regs & lo = in.in_regs;
        !           301:         const ata_in_regs & hi = in.in_regs.prev;
        !           302:         // Note: all 'in.in_regs.prev.*' are always zero for 28-bit commands
        !           303:         cdb[ 3] = hi.features;
        !           304:         cdb[ 4] = lo.features;
        !           305:         cdb[ 5] = hi.sector_count;
        !           306:         cdb[ 6] = lo.sector_count;
        !           307:         cdb[ 7] = hi.lba_low;
        !           308:         cdb[ 8] = lo.lba_low;
        !           309:         cdb[ 9] = hi.lba_mid;
        !           310:         cdb[10] = lo.lba_mid;
        !           311:         cdb[11] = hi.lba_high;
        !           312:         cdb[12] = lo.lba_high;
        !           313:         cdb[13] = lo.device;
        !           314:         cdb[14] = lo.command;
        !           315:     }
        !           316: 
        !           317:     memset(&io_hdr, 0, sizeof(io_hdr));
        !           318:     if (0 == t_length) {
        !           319:         io_hdr.dxfer_dir = DXFER_NONE;
        !           320:         io_hdr.dxfer_len = 0;
        !           321:     } else if (t_dir) {         /* from device */
        !           322:         io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
        !           323:         io_hdr.dxfer_len = in.size;
        !           324:         io_hdr.dxferp = (unsigned char *)in.buffer;
        !           325:         memset(in.buffer, 0, in.size); // prefill with zeroes
        !           326:     } else {                    /* to device */
        !           327:         io_hdr.dxfer_dir = DXFER_TO_DEVICE;
        !           328:         io_hdr.dxfer_len = in.size;
        !           329:         io_hdr.dxferp = (unsigned char *)in.buffer;
        !           330:     }
        !           331:     io_hdr.cmnd = cdb;
        !           332:     io_hdr.cmnd_len = passthru_size;
        !           333:     io_hdr.sensep = sense;
        !           334:     io_hdr.max_sense_len = sizeof(sense);
        !           335:     io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
        !           336: 
        !           337:     scsi_device * scsidev = get_tunnel_dev();
        !           338:     if (!scsidev->scsi_pass_through(&io_hdr)) {
        !           339:         if (scsi_debugmode > 0)
        !           340:             pout("sat_device::ata_pass_through: scsi_pass_through() failed, "
        !           341:                  "errno=%d [%s]\n", scsidev->get_errno(), scsidev->get_errmsg());
        !           342:         return set_err(scsidev->get_err());
        !           343:     }
        !           344:     ardp = NULL;
        !           345:     ard_len = 0;
        !           346:     have_sense = sg_scsi_normalize_sense(io_hdr.sensep, io_hdr.resp_sense_len,
        !           347:                                          &ssh);
        !           348:     if (have_sense) {
        !           349:         /* look for SAT ATA Return Descriptor */
        !           350:         ardp = sg_scsi_sense_desc_find(io_hdr.sensep,
        !           351:                                        io_hdr.resp_sense_len,
        !           352:                                        ATA_RETURN_DESCRIPTOR);
        !           353:         if (ardp) {
        !           354:             ard_len = ardp[1] + 2;
        !           355:             if (ard_len < 12)
        !           356:                 ard_len = 12;
        !           357:             else if (ard_len > 14)
        !           358:                 ard_len = 14;
        !           359:         }
        !           360:         scsi_do_sense_disect(&io_hdr, &sinfo);
        !           361:         status = scsiSimpleSenseFilter(&sinfo);
        !           362:         if (0 != status) {
        !           363:             if (scsi_debugmode > 0) {
        !           364:                 pout("sat_device::ata_pass_through: scsi error: %s\n",
        !           365:                      scsiErrString(status));
        !           366:                 if (ardp && (scsi_debugmode > 1)) {
        !           367:                     pout("Values from ATA Return Descriptor are:\n");
        !           368:                     dStrHex((const char *)ardp, ard_len, 1);
        !           369:                 }
        !           370:             }
        !           371:             if (t_dir && (t_length > 0) && (in.direction == ata_cmd_in::data_in))
        !           372:                 memset(in.buffer, 0, in.size);
        !           373:             return set_err(EIO, "scsi error %s", scsiErrString(status));
        !           374:         }
        !           375:     }
        !           376:     if (ck_cond) {     /* expecting SAT specific sense data */
        !           377:         if (have_sense) {
        !           378:             if (ardp) {
        !           379:                 if (scsi_debugmode > 1) {
        !           380:                     pout("Values from ATA Return Descriptor are:\n");
        !           381:                     dStrHex((const char *)ardp, ard_len, 1);
        !           382:                 }
        !           383:                 // Set output registers
        !           384:                 ata_out_regs & lo = out.out_regs;
        !           385:                 lo.error        = ardp[ 3];
        !           386:                 lo.sector_count = ardp[ 5];
        !           387:                 lo.lba_low      = ardp[ 7];
        !           388:                 lo.lba_mid      = ardp[ 9];
        !           389:                 lo.lba_high     = ardp[11];
        !           390:                 lo.device       = ardp[12];
        !           391:                 lo.status       = ardp[13];
        !           392:                 if (in.in_regs.is_48bit_cmd()) {
        !           393:                     ata_out_regs & hi = out.out_regs.prev;
        !           394:                     hi.sector_count = ardp[ 4];
        !           395:                     hi.lba_low      = ardp[ 6];
        !           396:                     hi.lba_mid      = ardp[ 8];
        !           397:                     hi.lba_high     = ardp[10];
        !           398:                 }
        !           399:             }
        !           400:         }
        !           401:         if (ardp == NULL)
        !           402:             ck_cond = 0;       /* not the type of sense data expected */
        !           403:     }
        !           404:     if (0 == ck_cond) {
        !           405:         if (have_sense) {
        !           406:             if ((ssh.response_code >= 0x72) &&
        !           407:                 ((SCSI_SK_NO_SENSE == ssh.sense_key) ||
        !           408:                  (SCSI_SK_RECOVERED_ERR == ssh.sense_key)) &&
        !           409:                 (0 == ssh.asc) &&
        !           410:                 (SCSI_ASCQ_ATA_PASS_THROUGH == ssh.ascq)) {
        !           411:                 if (ardp) {
        !           412:                     if (scsi_debugmode > 0) {
        !           413:                         pout("Values from ATA Return Descriptor are:\n");
        !           414:                         dStrHex((const char *)ardp, ard_len, 1);
        !           415:                     }
        !           416:                     return set_err(EIO, "SAT command failed");
        !           417:                 }
        !           418:             }
        !           419:         }
        !           420:     }
        !           421:     return true;
        !           422: }
        !           423: 
        !           424: } // namespace
        !           425: 
        !           426: /////////////////////////////////////////////////////////////////////////////
        !           427: 
        !           428: /* Attempt an IDENTIFY DEVICE ATA command via SATL when packet_interface
        !           429:    is false otherwise attempt IDENTIFY PACKET DEVICE. If successful
        !           430:    return true, else false */
        !           431: 
        !           432: static bool has_sat_pass_through(ata_device * dev, bool packet_interface = false)
        !           433: {
        !           434:     /* Note:  malloc() ensures the read buffer lands on a single
        !           435:        page.  This avoids some bugs seen on LSI controlers under
        !           436:        FreeBSD */
        !           437:     char *data = (char *)malloc(512);
        !           438:     ata_cmd_in in;
        !           439:     in.in_regs.command = (packet_interface ? ATA_IDENTIFY_PACKET_DEVICE : ATA_IDENTIFY_DEVICE);
        !           440:     in.set_data_in(data, 1);
        !           441:     bool ret = dev->ata_pass_through(in);
        !           442:     free(data);
        !           443:     return ret;
        !           444: }
        !           445: 
        !           446: /////////////////////////////////////////////////////////////////////////////
        !           447: 
        !           448: /* Next two functions are borrowed from sg_lib.c in the sg3_utils
        !           449:    package. Same copyrght owner, same license as this file. */
        !           450: static int sg_scsi_normalize_sense(const unsigned char * sensep, int sb_len,
        !           451:                                    struct sg_scsi_sense_hdr * sshp)
        !           452: {
        !           453:     if (sshp)
        !           454:         memset(sshp, 0, sizeof(struct sg_scsi_sense_hdr));
        !           455:     if ((NULL == sensep) || (0 == sb_len) || (0x70 != (0x70 & sensep[0])))
        !           456:         return 0;
        !           457:     if (sshp) {
        !           458:         sshp->response_code = (0x7f & sensep[0]);
        !           459:         if (sshp->response_code >= 0x72) {  /* descriptor format */
        !           460:             if (sb_len > 1)
        !           461:                 sshp->sense_key = (0xf & sensep[1]);
        !           462:             if (sb_len > 2)
        !           463:                 sshp->asc = sensep[2];
        !           464:             if (sb_len > 3)
        !           465:                 sshp->ascq = sensep[3];
        !           466:             if (sb_len > 7)
        !           467:                 sshp->additional_length = sensep[7];
        !           468:         } else {                              /* fixed format */
        !           469:             if (sb_len > 2)
        !           470:                 sshp->sense_key = (0xf & sensep[2]);
        !           471:             if (sb_len > 7) {
        !           472:                 sb_len = (sb_len < (sensep[7] + 8)) ? sb_len :
        !           473:                                                       (sensep[7] + 8);
        !           474:                 if (sb_len > 12)
        !           475:                     sshp->asc = sensep[12];
        !           476:                 if (sb_len > 13)
        !           477:                     sshp->ascq = sensep[13];
        !           478:             }
        !           479:         }
        !           480:     }
        !           481:     return 1;
        !           482: }
        !           483: 
        !           484: 
        !           485: static const unsigned char * sg_scsi_sense_desc_find(const unsigned char * sensep,
        !           486:                                                      int sense_len, int desc_type)
        !           487: {
        !           488:     int add_sen_len, add_len, desc_len, k;
        !           489:     const unsigned char * descp;
        !           490: 
        !           491:     if ((sense_len < 8) || (0 == (add_sen_len = sensep[7])))
        !           492:         return NULL;
        !           493:     if ((sensep[0] < 0x72) || (sensep[0] > 0x73))
        !           494:         return NULL;
        !           495:     add_sen_len = (add_sen_len < (sense_len - 8)) ?
        !           496:                          add_sen_len : (sense_len - 8);
        !           497:     descp = &sensep[8];
        !           498:     for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
        !           499:         descp += desc_len;
        !           500:         add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
        !           501:         desc_len = add_len + 2;
        !           502:         if (descp[0] == desc_type)
        !           503:             return descp;
        !           504:         if (add_len < 0) /* short descriptor ?? */
        !           505:             break;
        !           506:     }
        !           507:     return NULL;
        !           508: }
        !           509: 
        !           510: 
        !           511: // Call scsi_pass_through and check sense.
        !           512: // TODO: Provide as member function of class scsi_device (?)
        !           513: static bool scsi_pass_through_and_check(scsi_device * scsidev,  scsi_cmnd_io * iop,
        !           514:                                         const char * msg = "")
        !           515: {
        !           516:   // Provide sense buffer
        !           517:   unsigned char sense[32] = {0, };
        !           518:   iop->sensep = sense;
        !           519:   iop->max_sense_len = sizeof(sense);
        !           520:   iop->timeout = SCSI_TIMEOUT_DEFAULT;
        !           521: 
        !           522:   // Run cmd
        !           523:   if (!scsidev->scsi_pass_through(iop)) {
        !           524:     if (scsi_debugmode > 0)
        !           525:       pout("%sscsi_pass_through() failed, errno=%d [%s]\n",
        !           526:            msg, scsidev->get_errno(), scsidev->get_errmsg());
        !           527:     return false;
        !           528:   }
        !           529: 
        !           530:   // Check sense
        !           531:   scsi_sense_disect sinfo;
        !           532:   scsi_do_sense_disect(iop, &sinfo);
        !           533:   int err = scsiSimpleSenseFilter(&sinfo);
        !           534:   if (err) {
        !           535:     if (scsi_debugmode > 0)
        !           536:       pout("%sscsi error: %s\n", msg, scsiErrString(err));
        !           537:     return scsidev->set_err(EIO, "scsi error %s", scsiErrString(err));
        !           538:   }
        !           539: 
        !           540:   return true;
        !           541: }
        !           542: 
        !           543: 
        !           544: /////////////////////////////////////////////////////////////////////////////
        !           545: 
        !           546: namespace sat {
        !           547: 
        !           548: /// Cypress USB Brigde support.
        !           549: 
        !           550: class usbcypress_device
        !           551: : public tunnelled_device<
        !           552:     /*implements*/ ata_device_with_command_set
        !           553:     /*by tunnelling through a*/, scsi_device
        !           554:   >
        !           555: {
        !           556: public:
        !           557:   usbcypress_device(smart_interface * intf, scsi_device * scsidev,
        !           558:     const char * req_type, unsigned char signature);
        !           559: 
        !           560:   virtual ~usbcypress_device() throw();
        !           561: 
        !           562: protected:
        !           563:   virtual int ata_command_interface(smart_command_set command, int select, char * data);
        !           564: 
        !           565:   unsigned char m_signature;
        !           566: };
        !           567: 
        !           568: 
        !           569: usbcypress_device::usbcypress_device(smart_interface * intf, scsi_device * scsidev,
        !           570:   const char * req_type, unsigned char signature)
        !           571: : smart_device(intf, scsidev->get_dev_name(), "sat", req_type),
        !           572:   tunnelled_device<ata_device_with_command_set, scsi_device>(scsidev),
        !           573:   m_signature(signature)
        !           574: {
        !           575:   set_info().info_name = strprintf("%s [USB Cypress]", scsidev->get_info_name());
        !           576: }
        !           577: 
        !           578: usbcypress_device::~usbcypress_device() throw()
        !           579: {
        !           580: }
        !           581: 
        !           582: 
        !           583: /* see cy7c68300c_8.pdf for more information */
        !           584: #define USBCYPRESS_PASSTHROUGH_LEN 16
        !           585: int usbcypress_device::ata_command_interface(smart_command_set command, int select, char *data)
        !           586: {
        !           587:     struct scsi_cmnd_io io_hdr;
        !           588:     unsigned char cdb[USBCYPRESS_PASSTHROUGH_LEN];
        !           589:     unsigned char sense[32];
        !           590:     int copydata = 0;
        !           591:     int outlen = 0;
        !           592:     int ck_cond = 0;    /* set to 1 to read register(s) back */
        !           593:     int t_dir = 1;      /* 0 -> to device, 1 -> from device */
        !           594:     int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */
        !           595:     int t_length = 0;   /* 0 -> no data transferred */
        !           596:     int feature = 0;
        !           597:     int ata_command = 0;
        !           598:     int sector_count = 0;
        !           599:     int lba_low = 0;
        !           600:     int lba_mid = 0;
        !           601:     int lba_high = 0;
        !           602:     int passthru_size = USBCYPRESS_PASSTHROUGH_LEN;
        !           603: 
        !           604:     memset(cdb, 0, sizeof(cdb));
        !           605:     memset(sense, 0, sizeof(sense));
        !           606: 
        !           607:     ata_command = ATA_SMART_CMD;
        !           608:     switch (command) {
        !           609:     case CHECK_POWER_MODE:
        !           610:         ata_command = ATA_CHECK_POWER_MODE;
        !           611:         ck_cond = 1;
        !           612:         copydata = 1;
        !           613:         break;
        !           614:     case READ_VALUES:           /* READ DATA */
        !           615:         feature = ATA_SMART_READ_VALUES;
        !           616:         sector_count = 1;     /* one (512 byte) block */
        !           617:         t_length = 2;   /* sector count holds count */
        !           618:         copydata = 512;
        !           619:         break;
        !           620:     case READ_THRESHOLDS:       /* obsolete */
        !           621:         feature = ATA_SMART_READ_THRESHOLDS;
        !           622:         sector_count = 1;     /* one (512 byte) block */
        !           623:         lba_low = 1;
        !           624:         t_length = 2;   /* sector count holds count */
        !           625:         copydata=512;
        !           626:         break;
        !           627:     case READ_LOG:
        !           628:         feature = ATA_SMART_READ_LOG_SECTOR;
        !           629:         sector_count = 1;     /* one (512 byte) block */
        !           630:         lba_low = select;
        !           631:         t_length = 2;   /* sector count holds count */
        !           632:         copydata = 512;
        !           633:         break;
        !           634:     case WRITE_LOG:
        !           635:         feature = ATA_SMART_WRITE_LOG_SECTOR;
        !           636:         sector_count = 1;     /* one (512 byte) block */
        !           637:         lba_low = select;
        !           638:         t_length = 2;   /* sector count holds count */
        !           639:         t_dir = 0;      /* to device */
        !           640:         outlen = 512;
        !           641:         break;
        !           642:     case IDENTIFY:
        !           643:         ata_command = ATA_IDENTIFY_DEVICE;
        !           644:         sector_count = 1;     /* one (512 byte) block */
        !           645:         t_length = 2;   /* sector count holds count */
        !           646:         copydata = 512;
        !           647:         break;
        !           648:     case PIDENTIFY:
        !           649:         ata_command = ATA_IDENTIFY_PACKET_DEVICE;
        !           650:         sector_count = 1;     /* one (512 byte) block */
        !           651:         t_length = 2;   /* sector count (7:0) holds count */
        !           652:         copydata = 512;
        !           653:         break;
        !           654:     case ENABLE:
        !           655:         feature = ATA_SMART_ENABLE;
        !           656:         lba_low = 1;
        !           657:         break;
        !           658:     case DISABLE:
        !           659:         feature = ATA_SMART_DISABLE;
        !           660:         lba_low = 1;
        !           661:         break;
        !           662:     case STATUS:
        !           663:         // this command only says if SMART is working.  It could be
        !           664:         // replaced with STATUS_CHECK below.
        !           665:         feature = ATA_SMART_STATUS;
        !           666:         ck_cond = 1;
        !           667:         break;
        !           668:     case AUTO_OFFLINE:
        !           669:         feature = ATA_SMART_AUTO_OFFLINE;
        !           670:         sector_count = select;   // YET NOTE - THIS IS A NON-DATA COMMAND!!
        !           671:         break;
        !           672:     case AUTOSAVE:
        !           673:         feature = ATA_SMART_AUTOSAVE;
        !           674:         sector_count = select;   // YET NOTE - THIS IS A NON-DATA COMMAND!!
        !           675:         break;
        !           676:     case IMMEDIATE_OFFLINE:
        !           677:         feature = ATA_SMART_IMMEDIATE_OFFLINE;
        !           678:         lba_low = select;
        !           679:         break;
        !           680:     case STATUS_CHECK:
        !           681:         // This command uses HDIO_DRIVE_TASK and has different syntax than
        !           682:         // the other commands.
        !           683:         feature = ATA_SMART_STATUS;      /* SMART RETURN STATUS */
        !           684:         ck_cond = 1;
        !           685:         break;
        !           686:     default:
        !           687:         pout("Unrecognized command %d in usbcypress_device::ata_command_interface()\n"
        !           688:              "Please contact " PACKAGE_BUGREPORT "\n", command);
        !           689:         errno=ENOSYS;
        !           690:         return -1;
        !           691:     }
        !           692:     if (ATA_SMART_CMD == ata_command) {
        !           693:         lba_mid = 0x4f;
        !           694:         lba_high = 0xc2;
        !           695:     }
        !           696: 
        !           697:     cdb[0] = m_signature; // bVSCBSignature : vendor-specific command
        !           698:     cdb[1] = 0x24; // bVSCBSubCommand : 0x24 for ATACB
        !           699:     cdb[2] = 0x0;
        !           700:     if (ata_command == ATA_IDENTIFY_DEVICE || ata_command == ATA_IDENTIFY_PACKET_DEVICE)
        !           701:         cdb[2] |= (1<<7); //set  IdentifyPacketDevice for these cmds
        !           702:     cdb[3] = 0xff - (1<<0) - (1<<6); //features, sector count, lba low, lba med
        !           703:                                      // lba high, command are valid
        !           704:     cdb[4] = byte_block; //TransferBlockCount : 512
        !           705: 
        !           706: 
        !           707:     cdb[6] = feature;
        !           708:     cdb[7] = sector_count;
        !           709:     cdb[8] = lba_low;
        !           710:     cdb[9] = lba_mid;
        !           711:     cdb[10] = lba_high;
        !           712:     cdb[12] = ata_command;
        !           713: 
        !           714:     memset(&io_hdr, 0, sizeof(io_hdr));
        !           715:     if (0 == t_length) {
        !           716:         io_hdr.dxfer_dir = DXFER_NONE;
        !           717:         io_hdr.dxfer_len = 0;
        !           718:     } else if (t_dir) {         /* from device */
        !           719:         io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
        !           720:         io_hdr.dxfer_len = copydata;
        !           721:         io_hdr.dxferp = (unsigned char *)data;
        !           722:         memset(data, 0, copydata); /* prefill with zeroes */
        !           723:     } else {                    /* to device */
        !           724:         io_hdr.dxfer_dir = DXFER_TO_DEVICE;
        !           725:         io_hdr.dxfer_len = outlen;
        !           726:         io_hdr.dxferp = (unsigned char *)data;
        !           727:     }
        !           728:     io_hdr.cmnd = cdb;
        !           729:     io_hdr.cmnd_len = passthru_size;
        !           730:     io_hdr.sensep = sense;
        !           731:     io_hdr.max_sense_len = sizeof(sense);
        !           732:     io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
        !           733: 
        !           734:     scsi_device * scsidev = get_tunnel_dev();
        !           735:     if (!scsidev->scsi_pass_through(&io_hdr)) {
        !           736:         if (scsi_debugmode > 0)
        !           737:             pout("usbcypress_device::ata_command_interface: scsi_pass_through() failed, "
        !           738:                  "errno=%d [%s]\n", scsidev->get_errno(), scsidev->get_errmsg());
        !           739:         set_err(scsidev->get_err());
        !           740:         return -1;
        !           741:     }
        !           742: 
        !           743:     // if there is a sense the command failed or the
        !           744:     // device doesn't support usbcypress
        !           745:     if (io_hdr.scsi_status == SCSI_STATUS_CHECK_CONDITION && 
        !           746:             sg_scsi_normalize_sense(io_hdr.sensep, io_hdr.resp_sense_len, NULL)) {
        !           747:         return -1;
        !           748:     }
        !           749:     if (ck_cond) {
        !           750:         unsigned char ardp[8];
        !           751:         int ard_len = 8;
        !           752:         /* XXX this is racy if there other scsi command between
        !           753:          * the first usbcypress command and this one
        !           754:          */
        !           755:         //pout("If you got strange result, please retry without traffic on the disc\n");
        !           756:         /* we use the same command as before, but we set
        !           757:          * * the read taskfile bit, for not executing usbcypress command,
        !           758:          * * but reading register selected in srb->cmnd[4]
        !           759:          */
        !           760:         cdb[2] = (1<<0); /* ask read taskfile */
        !           761:         memset(sense, 0, sizeof(sense));
        !           762: 
        !           763:         /* transfert 8 bytes */
        !           764:         memset(&io_hdr, 0, sizeof(io_hdr));
        !           765:         io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
        !           766:         io_hdr.dxfer_len = ard_len;
        !           767:         io_hdr.dxferp = (unsigned char *)ardp;
        !           768:         memset(ardp, 0, ard_len); /* prefill with zeroes */
        !           769: 
        !           770:         io_hdr.cmnd = cdb;
        !           771:         io_hdr.cmnd_len = passthru_size;
        !           772:         io_hdr.sensep = sense;
        !           773:         io_hdr.max_sense_len = sizeof(sense);
        !           774:         io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
        !           775: 
        !           776: 
        !           777:         if (!scsidev->scsi_pass_through(&io_hdr)) {
        !           778:             if (scsi_debugmode > 0)
        !           779:                 pout("usbcypress_device::ata_command_interface: scsi_pass_through() failed, "
        !           780:                      "errno=%d [%s]\n", scsidev->get_errno(), scsidev->get_errmsg());
        !           781:             set_err(scsidev->get_err());
        !           782:             return -1;
        !           783:         }
        !           784:         // if there is a sense the command failed or the
        !           785:         // device doesn't support usbcypress
        !           786:         if (io_hdr.scsi_status == SCSI_STATUS_CHECK_CONDITION && 
        !           787:                 sg_scsi_normalize_sense(io_hdr.sensep, io_hdr.resp_sense_len, NULL)) {
        !           788:             return -1;
        !           789:         }
        !           790: 
        !           791: 
        !           792:         if (scsi_debugmode > 1) {
        !           793:             pout("Values from ATA Return Descriptor are:\n");
        !           794:             dStrHex((const char *)ardp, ard_len, 1);
        !           795:         }
        !           796: 
        !           797:         if (ATA_CHECK_POWER_MODE == ata_command)
        !           798:             data[0] = ardp[2];      /* sector count (0:7) */
        !           799:         else if (STATUS_CHECK == command) {
        !           800:             if ((ardp[4] == 0x4f) && (ardp[5] == 0xc2))
        !           801:                 return 0;    /* GOOD smart status */
        !           802:             if ((ardp[4] == 0xf4) && (ardp[5] == 0x2c))
        !           803:                 return 1;    // smart predicting failure, "bad" status
        !           804:             // We haven't gotten output that makes sense so
        !           805:             // print out some debugging info
        !           806:             syserror("Error SMART Status command failed");
        !           807:             pout("This may be due to a race in usbcypress\n");
        !           808:             pout("Retry without other disc access\n");
        !           809:             pout("Please get assistance from " PACKAGE_HOMEPAGE "\n");
        !           810:             pout("Values from ATA Return Descriptor are:\n");
        !           811:             dStrHex((const char *)ardp, ard_len, 1);
        !           812:             return -1;
        !           813:         }
        !           814:     }
        !           815:     return 0;
        !           816: }
        !           817: 
        !           818: #if 0 // Not used, see autodetect_sat_device() below.
        !           819: static int isprint_string(const char *s)
        !           820: {
        !           821:     while (*s) {
        !           822:         if (isprint(*s) == 0)
        !           823:             return 0;
        !           824:         s++;
        !           825:     }
        !           826:     return 1;
        !           827: }
        !           828: 
        !           829: /* Attempt an IDENTIFY DEVICE ATA or IDENTIFY PACKET DEVICE command
        !           830:    If successful return 1, else 0 */
        !           831: // TODO: Combine with has_sat_pass_through above
        !           832: static int has_usbcypress_pass_through(ata_device * atadev, const char *manufacturer, const char *product)
        !           833: {
        !           834:     struct ata_identify_device drive;
        !           835:     char model[40], serial[20], firm[8];
        !           836: 
        !           837:     /* issue the command and do a checksum if possible */
        !           838:     if (ataReadHDIdentity(atadev, &drive) < 0)
        !           839:         return 0;
        !           840: 
        !           841:     /* check if model string match, revision doesn't work for me */
        !           842:     format_ata_string(model, drive.model, 40);
        !           843:     if (*model == 0 || isprint_string(model) == 0)
        !           844:         return 0;
        !           845: 
        !           846:     if (manufacturer && strncmp(manufacturer, model, 8))
        !           847:         pout("manufacturer doesn't match in pass_through test\n");
        !           848:     if (product &&
        !           849:             strlen(model) > 8 && strncmp(product, model+8, strlen(model)-8))
        !           850:         pout("product doesn't match in pass_through test\n");
        !           851: 
        !           852:     /* check serial */
        !           853:     format_ata_string(serial, drive.serial_no, 20);
        !           854:     if (isprint_string(serial) == 0)
        !           855:         return 0;
        !           856:     format_ata_string(firm, drive.fw_rev, 8);
        !           857:     if (isprint_string(firm) == 0)
        !           858:         return 0;
        !           859:     return 1;
        !           860: }
        !           861: #endif
        !           862: 
        !           863: /////////////////////////////////////////////////////////////////////////////
        !           864: 
        !           865: /// JMicron USB Bridge support.
        !           866: 
        !           867: class usbjmicron_device
        !           868: : public tunnelled_device<
        !           869:     /*implements*/ ata_device,
        !           870:     /*by tunnelling through a*/ scsi_device
        !           871:   >
        !           872: {
        !           873: public:
        !           874:   usbjmicron_device(smart_interface * intf, scsi_device * scsidev,
        !           875:                     const char * req_type, bool ata_48bit_support, int port);
        !           876: 
        !           877:   virtual ~usbjmicron_device() throw();
        !           878: 
        !           879:   virtual bool open();
        !           880: 
        !           881:   virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
        !           882: 
        !           883: private:
        !           884:   bool get_registers(unsigned short addr, unsigned char * buf, unsigned short size);
        !           885: 
        !           886:   bool m_ata_48bit_support;
        !           887:   int m_port;
        !           888: };
        !           889: 
        !           890: 
        !           891: usbjmicron_device::usbjmicron_device(smart_interface * intf, scsi_device * scsidev,
        !           892:                                      const char * req_type, bool ata_48bit_support, int port)
        !           893: : smart_device(intf, scsidev->get_dev_name(), "usbjmicron", req_type),
        !           894:   tunnelled_device<ata_device, scsi_device>(scsidev),
        !           895:   m_ata_48bit_support(ata_48bit_support), m_port(port)
        !           896: {
        !           897:   set_info().info_name = strprintf("%s [USB JMicron]", scsidev->get_info_name());
        !           898: }
        !           899: 
        !           900: usbjmicron_device::~usbjmicron_device() throw()
        !           901: {
        !           902: }
        !           903: 
        !           904: 
        !           905: bool usbjmicron_device::open()
        !           906: {
        !           907:   // Open USB first
        !           908:   if (!tunnelled_device<ata_device, scsi_device>::open())
        !           909:     return false;
        !           910: 
        !           911:   // Detect port if not specified
        !           912:   if (m_port < 0) {
        !           913:     unsigned char regbuf[1] = {0};
        !           914:     if (!get_registers(0x720f, regbuf, sizeof(regbuf))) {
        !           915:       close();
        !           916:       return false;
        !           917:     }
        !           918: 
        !           919:     switch (regbuf[0] & 0x44) {
        !           920:       case 0x04:
        !           921:         m_port = 0; break;
        !           922:       case 0x40:
        !           923:         m_port = 1; break;
        !           924:       case 0x44:
        !           925:         close();
        !           926:         return set_err(EINVAL, "Two devices connected, try '-d usbjmicron,[01]'");
        !           927:       default:
        !           928:         close();
        !           929:         return set_err(ENODEV, "No device connected");
        !           930:     }
        !           931:   }
        !           932: 
        !           933:   return true;
        !           934: }
        !           935: 
        !           936: 
        !           937: bool usbjmicron_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
        !           938: {
        !           939:   if (!ata_cmd_is_ok(in,
        !           940:     true,  // data_out_support
        !           941:     false, // !multi_sector_support
        !           942:     m_ata_48bit_support) // limited, see below
        !           943:   )
        !           944:     return false;
        !           945: 
        !           946:   bool is_smart_status = (   in.in_regs.command  == ATA_SMART_CMD
        !           947:                           && in.in_regs.features == ATA_SMART_STATUS);
        !           948: 
        !           949:   // Support output registers for SMART STATUS
        !           950:   if (in.out_needed.is_set() && !is_smart_status)
        !           951:     return set_err(ENOSYS, "ATA output registers not supported");
        !           952: 
        !           953:   // Support 48-bit commands with zero high bytes
        !           954:   if (in.in_regs.is_real_48bit_cmd())
        !           955:     return set_err(ENOSYS, "48-bit ATA commands not fully supported");
        !           956: 
        !           957:   if (m_port < 0)
        !           958:     return set_err(EIO, "Unknown JMicron port");
        !           959: 
        !           960:   scsi_cmnd_io io_hdr;
        !           961:   memset(&io_hdr, 0, sizeof(io_hdr));
        !           962: 
        !           963:   bool rwbit = true;
        !           964:   unsigned char smart_status = 0;
        !           965: 
        !           966:   if (is_smart_status && in.out_needed.is_set()) {
        !           967:     io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
        !           968:     io_hdr.dxfer_len = 1;
        !           969:     io_hdr.dxferp = &smart_status;
        !           970:   }
        !           971:   else switch (in.direction) {
        !           972:     case ata_cmd_in::no_data:
        !           973:       io_hdr.dxfer_dir = DXFER_NONE;
        !           974:       break;
        !           975:     case ata_cmd_in::data_in:
        !           976:       io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
        !           977:       io_hdr.dxfer_len = in.size;
        !           978:       io_hdr.dxferp = (unsigned char *)in.buffer;
        !           979:       memset(in.buffer, 0, in.size);
        !           980:       break;
        !           981:     case ata_cmd_in::data_out:
        !           982:       io_hdr.dxfer_dir = DXFER_TO_DEVICE;
        !           983:       io_hdr.dxfer_len = in.size;
        !           984:       io_hdr.dxferp = (unsigned char *)in.buffer;
        !           985:       rwbit = false;
        !           986:       break;
        !           987:     default:
        !           988:       return set_err(EINVAL);
        !           989:   }
        !           990: 
        !           991:   // Build pass through command
        !           992:   unsigned char cdb[12];
        !           993:   cdb[ 0] = 0xdf;
        !           994:   cdb[ 1] = (rwbit ? 0x10 : 0x00);
        !           995:   cdb[ 2] = 0x00;
        !           996:   cdb[ 3] = (unsigned char)(io_hdr.dxfer_len >> 8);
        !           997:   cdb[ 4] = (unsigned char)(io_hdr.dxfer_len     );
        !           998:   cdb[ 5] = in.in_regs.features;
        !           999:   cdb[ 6] = in.in_regs.sector_count;
        !          1000:   cdb[ 7] = in.in_regs.lba_low;
        !          1001:   cdb[ 8] = in.in_regs.lba_mid;
        !          1002:   cdb[ 9] = in.in_regs.lba_high;
        !          1003:   cdb[10] = in.in_regs.device | (m_port == 0 ? 0xa0 : 0xb0);
        !          1004:   cdb[11] = in.in_regs.command;
        !          1005: 
        !          1006:   io_hdr.cmnd = cdb;
        !          1007:   io_hdr.cmnd_len = sizeof(cdb);
        !          1008: 
        !          1009:   scsi_device * scsidev = get_tunnel_dev();
        !          1010:   if (!scsi_pass_through_and_check(scsidev, &io_hdr,
        !          1011:          "usbjmicron_device::ata_pass_through: "))
        !          1012:     return set_err(scsidev->get_err());
        !          1013: 
        !          1014:   if (in.out_needed.is_set()) {
        !          1015:     if (is_smart_status) {
        !          1016:       switch (smart_status) {
        !          1017:         case 0x01: case 0xc2:
        !          1018:           out.out_regs.lba_high = 0xc2;
        !          1019:           out.out_regs.lba_mid = 0x4f;
        !          1020:           break;
        !          1021:         case 0x00: case 0x2c:
        !          1022:           out.out_regs.lba_high = 0x2c;
        !          1023:           out.out_regs.lba_mid = 0xf4;
        !          1024:           break;
        !          1025:       }
        !          1026:     }
        !          1027: 
        !          1028: #if 0 // Not needed for SMART STATUS, see also notes below
        !          1029:     else {
        !          1030:       // Read ATA output registers
        !          1031:       // NOTE: The register addresses are not valid for some older chip revisions
        !          1032:       // NOTE: There is a small race condition here!
        !          1033:       unsigned char regbuf[16] = {0, };
        !          1034:       if (!get_registers((m_port == 0 ? 0x8000 : 0x9000), regbuf, sizeof(regbuf)))
        !          1035:         return false;
        !          1036: 
        !          1037:       out.out_regs.sector_count = regbuf[ 0];
        !          1038:       out.out_regs.lba_mid      = regbuf[ 4];
        !          1039:       out.out_regs.lba_low      = regbuf[ 6];
        !          1040:       out.out_regs.device       = regbuf[ 9];
        !          1041:       out.out_regs.lba_high     = regbuf[10];
        !          1042:       out.out_regs.error        = regbuf[13];
        !          1043:       out.out_regs.status       = regbuf[14];
        !          1044:     }
        !          1045: #endif
        !          1046:   }
        !          1047: 
        !          1048:   return true;
        !          1049: }
        !          1050: 
        !          1051: bool usbjmicron_device::get_registers(unsigned short addr,
        !          1052:                                       unsigned char * buf, unsigned short size)
        !          1053: {
        !          1054:   unsigned char cdb[12];
        !          1055:   cdb[ 0] = 0xdf;
        !          1056:   cdb[ 1] = 0x10;
        !          1057:   cdb[ 2] = 0x00;
        !          1058:   cdb[ 3] = (unsigned char)(size >> 8);
        !          1059:   cdb[ 4] = (unsigned char)(size     );
        !          1060:   cdb[ 5] = 0x00;
        !          1061:   cdb[ 6] = (unsigned char)(addr >> 8);
        !          1062:   cdb[ 7] = (unsigned char)(addr     );
        !          1063:   cdb[ 8] = 0x00;
        !          1064:   cdb[ 9] = 0x00;
        !          1065:   cdb[10] = 0x00;
        !          1066:   cdb[11] = 0xfd;
        !          1067: 
        !          1068:   scsi_cmnd_io io_hdr;
        !          1069:   memset(&io_hdr, 0, sizeof(io_hdr));
        !          1070:   io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
        !          1071:   io_hdr.dxfer_len = size;
        !          1072:   io_hdr.dxferp = buf;
        !          1073:   io_hdr.cmnd = cdb;
        !          1074:   io_hdr.cmnd_len = sizeof(cdb);
        !          1075: 
        !          1076:   scsi_device * scsidev = get_tunnel_dev();
        !          1077:   if (!scsi_pass_through_and_check(scsidev, &io_hdr,
        !          1078:          "usbjmicron_device::get_registers: "))
        !          1079:     return set_err(scsidev->get_err());
        !          1080: 
        !          1081:   return true;
        !          1082: }
        !          1083: 
        !          1084: 
        !          1085: /////////////////////////////////////////////////////////////////////////////
        !          1086: 
        !          1087: /// SunplusIT USB Bridge support.
        !          1088: 
        !          1089: class usbsunplus_device
        !          1090: : public tunnelled_device<
        !          1091:     /*implements*/ ata_device,
        !          1092:     /*by tunnelling through a*/ scsi_device
        !          1093:   >
        !          1094: {
        !          1095: public:
        !          1096:   usbsunplus_device(smart_interface * intf, scsi_device * scsidev,
        !          1097:                     const char * req_type);
        !          1098: 
        !          1099:   virtual ~usbsunplus_device() throw();
        !          1100: 
        !          1101:   virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
        !          1102: };
        !          1103: 
        !          1104: 
        !          1105: usbsunplus_device::usbsunplus_device(smart_interface * intf, scsi_device * scsidev,
        !          1106:                                      const char * req_type)
        !          1107: : smart_device(intf, scsidev->get_dev_name(), "usbsunplus", req_type),
        !          1108:   tunnelled_device<ata_device, scsi_device>(scsidev)
        !          1109: {
        !          1110:   set_info().info_name = strprintf("%s [USB Sunplus]", scsidev->get_info_name());
        !          1111: }
        !          1112: 
        !          1113: usbsunplus_device::~usbsunplus_device() throw()
        !          1114: {
        !          1115: }
        !          1116: 
        !          1117: bool usbsunplus_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
        !          1118: {
        !          1119:   if (!ata_cmd_is_ok(in,
        !          1120:     true,  // data_out_support
        !          1121:     false, // !multi_sector_support
        !          1122:     true)  // ata_48bit_support
        !          1123:   )
        !          1124:     return false;
        !          1125: 
        !          1126:   scsi_cmnd_io io_hdr;
        !          1127:   unsigned char cdb[12];
        !          1128: 
        !          1129:   if (in.in_regs.is_48bit_cmd()) {
        !          1130:     // Set "previous" registers
        !          1131:     memset(&io_hdr, 0, sizeof(io_hdr));
        !          1132:     io_hdr.dxfer_dir = DXFER_NONE;
        !          1133: 
        !          1134:     cdb[ 0] = 0xf8;
        !          1135:     cdb[ 1] = 0x00;
        !          1136:     cdb[ 2] = 0x23; // Subcommand: Pass through presetting
        !          1137:     cdb[ 3] = 0x00;
        !          1138:     cdb[ 4] = 0x00;
        !          1139:     cdb[ 5] = in.in_regs.prev.features;
        !          1140:     cdb[ 6] = in.in_regs.prev.sector_count;
        !          1141:     cdb[ 7] = in.in_regs.prev.lba_low;
        !          1142:     cdb[ 8] = in.in_regs.prev.lba_mid;
        !          1143:     cdb[ 9] = in.in_regs.prev.lba_high;
        !          1144:     cdb[10] = 0x00;
        !          1145:     cdb[11] = 0x00;
        !          1146: 
        !          1147:     io_hdr.cmnd = cdb;
        !          1148:     io_hdr.cmnd_len = sizeof(cdb);
        !          1149: 
        !          1150:     scsi_device * scsidev = get_tunnel_dev();
        !          1151:     if (!scsi_pass_through_and_check(scsidev, &io_hdr,
        !          1152:            "usbsunplus_device::scsi_pass_through (presetting): "))
        !          1153:       return set_err(scsidev->get_err());
        !          1154:   }
        !          1155: 
        !          1156:   // Run Pass through command
        !          1157:   memset(&io_hdr, 0, sizeof(io_hdr));
        !          1158:   unsigned char protocol;
        !          1159:   switch (in.direction) {
        !          1160:     case ata_cmd_in::no_data:
        !          1161:       io_hdr.dxfer_dir = DXFER_NONE;
        !          1162:       protocol = 0x00;
        !          1163:       break;
        !          1164:     case ata_cmd_in::data_in:
        !          1165:       io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
        !          1166:       io_hdr.dxfer_len = in.size;
        !          1167:       io_hdr.dxferp = (unsigned char *)in.buffer;
        !          1168:       memset(in.buffer, 0, in.size);
        !          1169:       protocol = 0x10;
        !          1170:       break;
        !          1171:     case ata_cmd_in::data_out:
        !          1172:       io_hdr.dxfer_dir = DXFER_TO_DEVICE;
        !          1173:       io_hdr.dxfer_len = in.size;
        !          1174:       io_hdr.dxferp = (unsigned char *)in.buffer;
        !          1175:       protocol = 0x11;
        !          1176:       break;
        !          1177:     default:
        !          1178:       return set_err(EINVAL);
        !          1179:   }
        !          1180: 
        !          1181:   cdb[ 0] = 0xf8;
        !          1182:   cdb[ 1] = 0x00;
        !          1183:   cdb[ 2] = 0x22; // Subcommand: Pass through
        !          1184:   cdb[ 3] = protocol;
        !          1185:   cdb[ 4] = (unsigned char)(io_hdr.dxfer_len >> 9);
        !          1186:   cdb[ 5] = in.in_regs.features;
        !          1187:   cdb[ 6] = in.in_regs.sector_count;
        !          1188:   cdb[ 7] = in.in_regs.lba_low;
        !          1189:   cdb[ 8] = in.in_regs.lba_mid;
        !          1190:   cdb[ 9] = in.in_regs.lba_high;
        !          1191:   cdb[10] = in.in_regs.device | 0xa0;
        !          1192:   cdb[11] = in.in_regs.command;
        !          1193: 
        !          1194:   io_hdr.cmnd = cdb;
        !          1195:   io_hdr.cmnd_len = sizeof(cdb);
        !          1196: 
        !          1197:   scsi_device * scsidev = get_tunnel_dev();
        !          1198:   if (!scsi_pass_through_and_check(scsidev, &io_hdr,
        !          1199:          "usbsunplus_device::scsi_pass_through: "))
        !          1200:     // Returns sense key 0x03 (medium error) on ATA command error
        !          1201:     return set_err(scsidev->get_err());
        !          1202: 
        !          1203:   if (in.out_needed.is_set()) {
        !          1204:     // Read ATA output registers
        !          1205:     unsigned char regbuf[8] = {0, };
        !          1206:     memset(&io_hdr, 0, sizeof(io_hdr));
        !          1207:     io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
        !          1208:     io_hdr.dxfer_len = sizeof(regbuf);
        !          1209:     io_hdr.dxferp = regbuf;
        !          1210: 
        !          1211:     cdb[ 0] = 0xf8;
        !          1212:     cdb[ 1] = 0x00;
        !          1213:     cdb[ 2] = 0x21; // Subcommand: Get status
        !          1214:     memset(cdb+3, 0, sizeof(cdb)-3);
        !          1215:     io_hdr.cmnd = cdb;
        !          1216:     io_hdr.cmnd_len = sizeof(cdb);
        !          1217: 
        !          1218:     if (!scsi_pass_through_and_check(scsidev, &io_hdr,
        !          1219:            "usbsunplus_device::scsi_pass_through (get registers): "))
        !          1220:       return set_err(scsidev->get_err());
        !          1221: 
        !          1222:     out.out_regs.error        = regbuf[1];
        !          1223:     out.out_regs.sector_count = regbuf[2];
        !          1224:     out.out_regs.lba_low      = regbuf[3];
        !          1225:     out.out_regs.lba_mid      = regbuf[4];
        !          1226:     out.out_regs.lba_high     = regbuf[5];
        !          1227:     out.out_regs.device       = regbuf[6];
        !          1228:     out.out_regs.status       = regbuf[7];
        !          1229:   }
        !          1230: 
        !          1231:   return true;
        !          1232: }
        !          1233: 
        !          1234: 
        !          1235: } // namespace
        !          1236: 
        !          1237: using namespace sat;
        !          1238: 
        !          1239: 
        !          1240: /////////////////////////////////////////////////////////////////////////////
        !          1241: 
        !          1242: // Return ATA->SCSI filter for SAT or USB.
        !          1243: 
        !          1244: ata_device * smart_interface::get_sat_device(const char * type, scsi_device * scsidev)
        !          1245: {
        !          1246:   if (!strncmp(type, "sat", 3)) {
        !          1247:     int ptlen = 0, n1 = -1, n2 = -1;
        !          1248:     if (!(((sscanf(type, "sat%n,%d%n", &n1, &ptlen, &n2) == 1 && n2 == (int)strlen(type)) || n1 == (int)strlen(type))
        !          1249:         && (ptlen == 0 || ptlen == 12 || ptlen == 16))) {
        !          1250:       set_err(EINVAL, "Option '-d sat,<n>' requires <n> to be 0, 12 or 16");
        !          1251:       return 0;
        !          1252:     }
        !          1253:     return new sat_device(this, scsidev, type, ptlen);
        !          1254:   }
        !          1255: 
        !          1256:   else if (!strncmp(type, "usbcypress", 10)) {
        !          1257:     unsigned signature = 0x24; int n1 = -1, n2 = -1;
        !          1258:     if (!(((sscanf(type, "usbcypress%n,0x%x%n", &n1, &signature, &n2) == 1 && n2 == (int)strlen(type)) || n1 == (int)strlen(type))
        !          1259:           && signature <= 0xff)) {
        !          1260:       set_err(EINVAL, "Option '-d usbcypress,<n>' requires <n> to be "
        !          1261:                       "an hexadecimal number between 0x0 and 0xff");
        !          1262:       return 0;
        !          1263:     }
        !          1264:     return new usbcypress_device(this, scsidev, type, signature);
        !          1265:   }
        !          1266: 
        !          1267:   else if (!strncmp(type, "usbjmicron", 10)) {
        !          1268:     const char * t = type + 10;
        !          1269:     bool ata_48bit_support = false;
        !          1270:     if (!strncmp(t, ",x", 2)) {
        !          1271:       t += 2;
        !          1272:       ata_48bit_support = true;
        !          1273:     }
        !          1274:     int port = -1, n = -1;
        !          1275:     if (*t && !(  (sscanf(t, ",%d%n", &port, &n) == 1
        !          1276:                 && n == (int)strlen(t) && 0 <= port && port <= 1))) {
        !          1277:       set_err(EINVAL, "Option '-d usbmicron[,x],<n>' requires <n> to be 0 or 1");
        !          1278:       return 0;
        !          1279:     }
        !          1280:     return new usbjmicron_device(this, scsidev, type, ata_48bit_support, port);
        !          1281:   }
        !          1282: 
        !          1283:   else if (!strcmp(type, "usbsunplus")) {
        !          1284:     return new usbsunplus_device(this, scsidev, type);
        !          1285:   }
        !          1286: 
        !          1287:   else {
        !          1288:     set_err(EINVAL, "Unknown USB device type '%s'", type);
        !          1289:     return 0;
        !          1290:   }
        !          1291: }
        !          1292: 
        !          1293: // Try to detect a SAT device behind a SCSI interface.
        !          1294: 
        !          1295: ata_device * smart_interface::autodetect_sat_device(scsi_device * scsidev,
        !          1296:   const unsigned char * inqdata, unsigned inqsize)
        !          1297: {
        !          1298:   if (!scsidev->is_open())
        !          1299:     return 0;
        !          1300: 
        !          1301:   // SAT ?
        !          1302:   if (inqdata && inqsize >= 36 && !memcmp(inqdata + 8, "ATA     ", 8)) { // TODO: Linux-specific?
        !          1303:     ata_device_auto_ptr atadev( new sat_device(this, scsidev, "") , scsidev);
        !          1304:     if (has_sat_pass_through(atadev.get()))
        !          1305:       return atadev.release(); // Detected SAT
        !          1306:   }
        !          1307: 
        !          1308:   return 0;
        !          1309: }
        !          1310: 
        !          1311: 
        !          1312: /////////////////////////////////////////////////////////////////////////////
        !          1313: // USB device type detection
        !          1314: 
        !          1315: // Format USB ID for error messages
        !          1316: static std::string format_usb_id(int vendor_id, int product_id, int version)
        !          1317: {
        !          1318:   if (version >= 0)
        !          1319:     return strprintf("[0x%04x:0x%04x (0x%03x)]", vendor_id, product_id, version);
        !          1320:   else
        !          1321:     return strprintf("[0x%04x:0x%04x]", vendor_id, product_id);
        !          1322: }
        !          1323: 
        !          1324: // Get type name for USB device with known VENDOR:PRODUCT ID.
        !          1325: const char * smart_interface::get_usb_dev_type_by_id(int vendor_id, int product_id,
        !          1326:                                                      int version /*= -1*/)
        !          1327: {
        !          1328:   usb_dev_info info, info2;
        !          1329:   int n = lookup_usb_device(vendor_id, product_id, version, info, info2);
        !          1330: 
        !          1331:   if (n <= 0) {
        !          1332:     set_err(EINVAL, "Unknown USB bridge %s",
        !          1333:             format_usb_id(vendor_id, product_id, version).c_str());
        !          1334:     return 0;
        !          1335:   }
        !          1336: 
        !          1337:   if (n > 1) {
        !          1338:     set_err(EINVAL, "USB bridge %s type is ambiguous: '%s' or '%s'",
        !          1339:             format_usb_id(vendor_id, product_id, version).c_str(),
        !          1340:             (!info.usb_type.empty()  ? info.usb_type.c_str()  : "[unsupported]"),
        !          1341:             (!info2.usb_type.empty() ? info2.usb_type.c_str() : "[unsupported]"));
        !          1342:     return 0;
        !          1343:   }
        !          1344: 
        !          1345:   if (info.usb_type.empty()) {
        !          1346:     set_err(ENOSYS, "Unsupported USB bridge %s",
        !          1347:             format_usb_id(vendor_id, product_id, version).c_str());
        !          1348:     return 0;
        !          1349:   }
        !          1350: 
        !          1351:   // TODO: change return type to std::string
        !          1352:   static std::string type;
        !          1353:   type = info.usb_type;
        !          1354:   return type.c_str();
        !          1355: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>