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>