From 06b7c5fcb604ab6a7ccea41ce9b8fa36e6e07667 Mon Sep 17 00:00:00 2001 From: chrfranke <chrfranke@4ea69e1a-61f1-4043-bf83-b5c94c648137> Date: Tue, 27 Apr 2010 20:31:47 +0000 Subject: [PATCH] Read USB ID info from drivedb.h (ticket #44). git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/trunk@3087 4ea69e1a-61f1-4043-bf83-b5c94c648137 --- smartmontools/CHANGELOG | 2 + smartmontools/NEWS | 1 + smartmontools/drivedb.h | 363 +++++++++++++++++++++++++++++++++- smartmontools/knowndrives.cpp | 235 +++++++++++++++++----- smartmontools/knowndrives.h | 16 +- smartmontools/scsiata.cpp | 144 ++------------ smartmontools/smartctl.8.in | 8 + 7 files changed, 587 insertions(+), 182 deletions(-) diff --git a/smartmontools/CHANGELOG b/smartmontools/CHANGELOG index 7cb3e1f25..a75e7cff1 100644 --- a/smartmontools/CHANGELOG +++ b/smartmontools/CHANGELOG @@ -43,6 +43,8 @@ NOTES FOR FUTURE RELEASES: see TODO file. <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE> + [CF] Read USB ID info from drivedb.h (ticket #44). + [CF] Create branch RELEASE_5_39_DRIVEDB with last drivedb.h file compatible with smartmontools 5.39[.1]. diff --git a/smartmontools/NEWS b/smartmontools/NEWS index 56661b221..f8c02260f 100644 --- a/smartmontools/NEWS +++ b/smartmontools/NEWS @@ -13,6 +13,7 @@ Summary: smartmontools release 5.40 - configure: New default value for '--with-docdir'. - Drive database is in a separate source file 'drivedb.h' which can be downloaded from SVN. +- USB ID info is now included in 'drivedb.h'. - New script 'update-smart-drivedb'. - smartd libcap-ng support, option '-C, --capabilities'. - smartctl option '-l scterc[,...]' to get/set the diff --git a/smartmontools/drivedb.h b/smartmontools/drivedb.h index c90753946..8fbcd2916 100644 --- a/smartmontools/drivedb.h +++ b/smartmontools/drivedb.h @@ -32,7 +32,7 @@ * modelfamily Informal string about the model family/series of a * device. Set to "" if no info (apart from device id) * known. The entry is ignored if this string starts with - * a dollar sign. + * a dollar sign. Must not start with "USB:", see below. * modelregexp POSIX extended regular expression to match the model of * a device. This should never be "". * firmwareregexp POSIX extended regular expression to match a devices's @@ -53,6 +53,23 @@ * The table will be searched from the start to end or until the first match, * so the order in the table is important for distinct entries that could match * the same drive. + * + * + * Format for USB ID entries: + * + * modelfamily String with format "USB: DEVICE; BRIDGE" where + * DEVICE is the name of the device and BRIDGE is + * the name of the USB bridge. Both may be empty + * if no info known. + * modelregexp POSIX extended regular expression to match the USB + * vendor:product ID in hex notation ("0x1234:0xabcd"). + * This should never be "". + * firmwareregexp POSIX extended regular expression to match the USB + * bcdDevice info. Only compared during search if other + * entries with same USB vendor:product ID exist. + * warningmsg Not used yet. + * presets String with one device type ('-d') option. + * */ /* @@ -1499,6 +1516,350 @@ const drive_settings builtin_knowndrives[] = { "QUANTUM FIREBALLP KA(9|10).1", "", "", "" }, + + //////////////////////////////////////////////////// + // USB ID entries + //////////////////////////////////////////////////// + + // Cypress + { "USB: ; Cypress CY7C68300A (AT2)", + "0x04b4:0x6830", + "0x0001", + "", + "" + }, + { "USB: ; Cypress CY7C68300B/C (AT2LP)", + "0x04b4:0x6830", + "0x0240", + "", + "-d usbcypress" + }, + // Myson Century + { "USB: ; Myson Century CS8818", + "0x04cf:0x8818", + "0xb007", + "", + "" + }, + // Samsung + { "USB: Samsung Story Station; ", + "0x04e8:0x5f06", + "", + "", + "-d sat" + }, + // Sunplus + { "USB: ; SunPlus SPDIF215", + "0x04fc:0x0c15", + "0xf615", + "", + "-d usbsunplus" + }, + { "USB: ; SunPlus SPDIF225", // USB+SATA->SATA + "0x04fc:0x0c25", + "0x0103", + "", + "-d usbsunplus" + }, + // Iomega + { "USB: Iomega LPHD080-0; ", + "0x059b:0x0272", + "", + "", + "-d usbcypress" + }, + { "USB: Iomega MDHD500-U; ", + "0x059b:0x0275", + "0x0001", + "", + "" + }, + // LaCie + { "USB: LaCie hard disk (FA Porsche design); ", + "0x059f:0x0651", + "", + "", + "" + }, + { "USB: LaCie hard disk (Neil Poulton design); ", + "0x059f:0x1018", + "", + "", + "-d sat" + }, + { "USB: LaCie Desktop Hard Drive; JMicron", + "0x059f:0x1019", + "", + "", + "-d usbjmicron" + }, + // In-System Design + { "USB: ; In-System/Cypress ISD-300A1", + "0x05ab:0x0060", + "0x1101", + "", + "-d usbcypress" + }, + // Genesys Logic + { "USB: ; Genesys Logic GL881E", + "0x05e3:0x0702", + "", + "", + "" + }, + { "USB: ; Genesys Logic", // TODO: requires '-T permissive' + "0x05e3:0x0718", + "0x0041", + "", + "-d sat" + }, + // Prolific + { "USB: ; Prolific PL2507", // USB->PATA + "0x067b:0x2507", + "", + "", + "" + }, + { "USB: ; Prolific PL3507", // USB+IEE1394->PATA + "0x067b:0x3507", + "0x0001", + "", + "" + }, + // Freecom + { "USB: Freecom Hard Drive XS; Sunplus", + "0x07ab:0xfc8e", + "0x010f", + "", + "-d usbsunplus" + }, + // Toshiba + { "USB: Toshiba PX1270E-1G16; Sunplus", + "0x0930:0x0b03", + "", + "", + "-d usbsunplus" + }, + { "USB: Toshiba PX1396E-3T01; Sunplus", // similar to Dura Micro 501 + "0x0930:0x0b09", + "", + "", + "-d usbsunplus" + }, + { "USB: Seagate FreeAgent Go; ", + "0x0bc2:0x2(000|100|101)", + "", + "", + "-d sat" + }, + { "USB: Seagate FreeAgent Go FW; ", + "0x0bc2:0x2200", + "", + "", + "-d sat" + }, + { "USB: Seagate Expansion Portable; ", + "0x0bc2:0x2300", + "", + "", + "-d sat" + }, + { "USB: Seagate FreeAgent Desktop; ", + "0x0bc2:0x3000", + "", + "", + "-d sat" + }, + { "USB: Seagate FreeAgent Desk; ", + "0x0bc2:0x3001", + "", + "", + "-d sat" + }, + // Dura Micro + { "USB: Dura Micro 509; Sunplus", + "0x0c0b:0xb159", + "0x0103", + "", + "-d usbsunplus" + }, + // Maxtor + { "USB: Maxtor OneTouch 4; ", + "0x0d49:0x7310", + "0x0125", + "", + "-d sat" + }, + { "USB: Maxtor OneTouch 4 Mini; ", + "0x0d49:0x7350", + "0x0125", + "", + "-d sat" + }, + { "USB: Maxtor Basics Desktop; ", + "0x0d49:0x7410", + "0x0122", + "", + "-d sat" + }, + { "USB: Maxtor Basics Portable; ", + "0x0d49:0x7450", + "0x0122", + "", + "-d sat" + }, + // Western Digital + { "USB: WD My Passport (IDE); Cypress", + "0x1058:0x0701", + "0x0240", + "", + "-d usbcypress" + }, + { "USB: WD My Passport Portable; ", + "0x1058:0x0702", + "0x0102", + "", + "-d sat" + }, + { "USB: WD My Passport Essential; ", + "0x1058:0x0704", + "0x0175", + "", + "-d sat" + }, + { "USB: WD My Passport Elite; ", + "0x1058:0x0705", + "0x0175", + "", + "-d sat" + }, + { "USB: WD My Passport 070A; ", + "0x1058:0x070a", + "0x1028", + "", + "-d sat" + }, + { "USB: WD My Book ES; ", + "0x1058:0x0906", + "0x0012", + "", + "-d sat" + }, + { "USB: WD Elements Desktop; ", + "0x1058:0x1001", + "0x0104", + "", + "-d sat" + }, + { "USB: WD Elements Desktop WDE1UBK...; ", + "0x1058:0x1003", + "0x0175", + "", + "-d sat" + }, + { "USB: WD Elements; ", + "0x1058:0x1010", + "0x0105", + "", + "-d sat" + }, + { "USB: WD My Book Essential; ", + "0x1058:0x1100", + "0x0165", + "", + "-d sat" + }, + { "USB: WD My Book; ", + "0x1058:0x1102", + "0x1028", + "", + "-d sat" + }, + { "USB: WD My Book Essential; ", + "0x1058:0x1110", + "0x1030", + "", + "-d sat" + }, + // A-DATA + { "USB: A-DATA SH93; ", + "0x125f:0xa93a", + "0x0150", + "", + "-d usbcypress" + }, + // Initio + { "USB: ; Initio 316000", + "0x13fd:0x0540", + "", + "", + "" + }, + { "USB: ; Initio", // USB->SATA + "0x13fd:0x1240", + "0x0104", + "", + "-d sat" + }, + { "USB: ; Initio", // USB+SATA->SATA + "0x13fd:0x1340", + "0x0208", + "", + "-d sat" + }, + // JMicron + { "USB: ; JMicron JM20329", // USB->SATA + "0x152d:0x2329", + "0x0100", + "", + "-d usbjmicron" + }, + { "USB: ; JMicron JM20336", // USB+SATA->SATA, USB->2xSATA + "0x152d:0x2336", + "0x0100", + "", + "-d usbjmicron,x" + }, + { "USB: ; JMicron JM20337/8", // USB->SATA+PATA, USB+SATA->PATA + "0x152d:0x2338", + "0x0100", + "", + "-d usbjmicron" + }, + { "USB: ; JMicron JM20339", // USB->SATA + "0x152d:0x2339", + "0x0100", + "", + "-d usbjmicron,x" + }, + // Verbatim + { "USB: Verbatim FW/USB160; Oxford OXUF934SSA-LQAG", // USB+IEE1394->SATA + "0x18a5:0x0215", + "0x0001", + "", + "-d sat" + }, + // SunplusIT + { "USB: ; SunplusIT", + "0x1bcf:0x0c31", + "", + "", + "-d usbsunplus" + }, + // Hitachi/SimpleTech + { "USB: Hitachi/SimpleTech; JMicron", // 1TB + "0x4971:0xce17", + "", + "", + "-d usbjmicron" + }, + // OnSpec + { "USB: ; OnSpec", // USB->PATA + "0x55aa:0x2b00", + "0x0100", + "", + "" + }, /* }; // builtin_knowndrives[] */ diff --git a/smartmontools/knowndrives.cpp b/smartmontools/knowndrives.cpp index 79e538249..0776b81cd 100644 --- a/smartmontools/knowndrives.cpp +++ b/smartmontools/knowndrives.cpp @@ -4,8 +4,8 @@ * Home page of code is: http://smartmontools.sourceforge.net * Address of support mailing list: smartmontools-support@lists.sourceforge.net * - * Copyright (C) 2003-9 Philip Williams, Bruce Allen - * Copyright (C) 2008-9 Christian Franke <smartmontools-support@lists.sourceforge.net> + * Copyright (C) 2003-10 Philip Williams, Bruce Allen + * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -140,6 +140,18 @@ const char * drive_database::copy_string(const char * src) static drive_database knowndrives; +// Return true if modelfamily string describes entry for USB ID +static bool is_usb_modelfamily(const char * modelfamily) +{ + return !strncmp(modelfamily, "USB:", 4); +} + +// Return true if entry for USB ID +static inline bool is_usb_entry(const drive_settings * dbentry) +{ + return is_usb_modelfamily(dbentry->modelfamily); +} + // Compile regular expression, print message on failure. static bool compile(regular_expression & regex, const char *pattern) { @@ -173,6 +185,10 @@ const drive_settings * lookup_drive(const char * model, const char * firmware) firmware = ""; for (unsigned i = 0; i < knowndrives.size(); i++) { + // Skip USB entries + if (is_usb_entry(&knowndrives[i])) + continue; + // Check whether model matches the regular expression in knowndrives[i]. if (!match(knowndrives[i].modelregexp, model)) continue; @@ -190,9 +206,10 @@ const drive_settings * lookup_drive(const char * model, const char * firmware) return 0; } -// Parse '-v' and '-F' options in preset string, return false on error. -static bool parse_presets(const char * presets, ata_vendor_attr_defs & defs, - unsigned char & fix_firmwarebug) + +// Parse drive or USB options in preset string, return false on error. +static bool parse_db_presets(const char * presets, ata_vendor_attr_defs * defs, + unsigned char * fix_firmwarebug, std::string * type) { for (int i = 0; ; ) { i += strspn(presets+i, " \t"); @@ -201,12 +218,12 @@ static bool parse_presets(const char * presets, ata_vendor_attr_defs & defs, char opt, arg[40+1+13]; int len = -1; if (!(sscanf(presets+i, "-%c %40[^ ]%n", &opt, arg, &len) >= 2 && len > 0)) return false; - if (opt == 'v') { + if (opt == 'v' && defs) { // Parse "-v N,format[,name]" - if (!parse_attribute_def(arg, defs, PRIOR_DATABASE)) + if (!parse_attribute_def(arg, *defs, PRIOR_DATABASE)) return false; } - else if (opt == 'F') { + else if (opt == 'F' && fix_firmwarebug) { unsigned char fix; if (!strcmp(arg, "samsung")) fix = FIX_SAMSUNG; @@ -217,8 +234,12 @@ static bool parse_presets(const char * presets, ata_vendor_attr_defs & defs, else return false; // Set only if not set by user - if (fix_firmwarebug == FIX_NOTSPECIFIED) - fix_firmwarebug = fix; + if (*fix_firmwarebug == FIX_NOTSPECIFIED) + *fix_firmwarebug = fix; + } + else if (opt == 'd' && type) { + // TODO: Check valid types + *type = arg; } else return false; @@ -228,6 +249,83 @@ static bool parse_presets(const char * presets, ata_vendor_attr_defs & defs, return true; } +// Parse '-v' and '-F' options in preset string, return false on error. +static inline bool parse_presets(const char * presets, + ata_vendor_attr_defs & defs, + unsigned char & fix_firmwarebug) +{ + return parse_db_presets(presets, &defs, &fix_firmwarebug, 0); +} + +// Parse '-d' option in preset string, return false on error. +static inline bool parse_usb_type(const char * presets, std::string & type) +{ + return parse_db_presets(presets, 0, 0, &type); +} + +// Parse "USB: [DEVICE] ; [BRIDGE]" string +static void parse_usb_names(const char * names, usb_dev_info & info) +{ + int n1 = -1, n2 = -1, n3 = -1; + sscanf(names, "USB: %n%*[^;]%n; %n", &n1, &n2, &n3); + if (0 < n1 && n1 < n2) + info.usb_device.assign(names+n1, n2-n1); + else + sscanf(names, "USB: ; %n", &n3); + if (0 < n3) + info.usb_bridge = names+n3; +} + +// Search drivedb for USB device with vendor:product ID. +int lookup_usb_device(int vendor_id, int product_id, int bcd_device, + usb_dev_info & info, usb_dev_info & info2) +{ + // Format strings to match + char usb_id_str[16], bcd_dev_str[16]; + snprintf(usb_id_str, sizeof(usb_id_str), "0x%04x:0x%04x", vendor_id, product_id); + if (bcd_device >= 0) + snprintf(bcd_dev_str, sizeof(bcd_dev_str), "0x%04x", bcd_device); + else + bcd_dev_str[0] = 0; + + int found = 0; + bool bcd_match = false; + for (unsigned i = 0; i < knowndrives.size(); i++) { + const drive_settings & dbentry = knowndrives[i]; + + // Skip drive entries + if (!is_usb_entry(&dbentry)) + continue; + + // Check whether USB vendor:product ID matches + if (!match(dbentry.modelregexp, usb_id_str)) + continue; + + // Parse '-d type' + usb_dev_info d; + if (!parse_usb_type(dbentry.presets, d.usb_type)) + return 0; // Syntax error + parse_usb_names(dbentry.modelfamily, d); + + // If two entries with same vendor:product ID have different + // types, use bcd_device (if provided by OS) to select entry. + bool bm = ( *bcd_dev_str && *dbentry.firmwareregexp + && match(dbentry.firmwareregexp, bcd_dev_str)); + + if (found == 0 || bm > bcd_match) { + info = d; found = 1; + bcd_match = bm; + } + else if (info.usb_type != d.usb_type && bm == bcd_match) { + // two different entries found + info2 = d; found = 2; + break; + } + } + + return found; +} + // Shows one entry of knowndrives[], returns #errors. static int showonepreset(const drive_settings * dbentry) { @@ -242,60 +340,80 @@ static int showonepreset(const drive_settings * dbentry) "this error to smartmontools developers at " PACKAGE_BUGREPORT ".\n"); return 1; } - + + bool usb = is_usb_entry(dbentry); + // print and check model and firmware regular expressions int errcnt = 0; regular_expression regex; - pout("%-*s %s\n", TABLEPRINTWIDTH, "MODEL REGEXP:", dbentry->modelregexp); + pout("%-*s %s\n", TABLEPRINTWIDTH, (!usb ? "MODEL REGEXP:" : "USB Vendor:Product:"), + dbentry->modelregexp); if (!compile(regex, dbentry->modelregexp)) errcnt++; - pout("%-*s %s\n", TABLEPRINTWIDTH, "FIRMWARE REGEXP:", *dbentry->firmwareregexp ? - dbentry->firmwareregexp : ".*"); // preserve old output (TODO: Change) + pout("%-*s %s\n", TABLEPRINTWIDTH, (!usb ? "FIRMWARE REGEXP:" : "USB bcdDevice:"), + *dbentry->firmwareregexp ? dbentry->firmwareregexp : ".*"); // preserve old output (TODO: Change) if (*dbentry->firmwareregexp && !compile(regex, dbentry->firmwareregexp)) errcnt++; - pout("%-*s %s\n", TABLEPRINTWIDTH, "MODEL FAMILY:", dbentry->modelfamily); - - // if there are any presets, then show them - unsigned char fix_firmwarebug = 0; - bool first_preset = true; - if (*dbentry->presets) { - ata_vendor_attr_defs defs; - if (!parse_presets(dbentry->presets, defs, fix_firmwarebug)) { - pout("Syntax error in preset option string \"%s\"\n", dbentry->presets); - errcnt++; + if (!usb) { + pout("%-*s %s\n", TABLEPRINTWIDTH, "MODEL FAMILY:", dbentry->modelfamily); + + // if there are any presets, then show them + unsigned char fix_firmwarebug = 0; + bool first_preset = true; + if (*dbentry->presets) { + ata_vendor_attr_defs defs; + if (!parse_presets(dbentry->presets, defs, fix_firmwarebug)) { + pout("Syntax error in preset option string \"%s\"\n", dbentry->presets); + errcnt++; + } + for (int i = 0; i < MAX_ATTRIBUTE_NUM; i++) { + if (defs[i].priority != PRIOR_DEFAULT) { + // Use leading zeros instead of spaces so that everything lines up. + pout("%-*s %03d %s\n", TABLEPRINTWIDTH, first_preset ? "ATTRIBUTE OPTIONS:" : "", + i, ata_get_smart_attr_name(i, defs).c_str()); + first_preset = false; + } + } } - for (int i = 0; i < MAX_ATTRIBUTE_NUM; i++) { - if (defs[i].priority != PRIOR_DEFAULT) { - // Use leading zeros instead of spaces so that everything lines up. - pout("%-*s %03d %s\n", TABLEPRINTWIDTH, first_preset ? "ATTRIBUTE OPTIONS:" : "", - i, ata_get_smart_attr_name(i, defs).c_str()); - first_preset = false; + if (first_preset) + pout("%-*s %s\n", TABLEPRINTWIDTH, "ATTRIBUTE OPTIONS:", "None preset; no -v options are required."); + + // describe firmwarefix + if (fix_firmwarebug) { + const char * fixdesc; + switch (fix_firmwarebug) { + case FIX_SAMSUNG: + fixdesc = "Fixes byte order in some SMART data (same as -F samsung)"; + break; + case FIX_SAMSUNG2: + fixdesc = "Fixes byte order in some SMART data (same as -F samsung2)"; + break; + case FIX_SAMSUNG3: + fixdesc = "Fixes completed self-test reported as in progress (same as -F samsung3)"; + break; + default: + fixdesc = "UNKNOWN"; errcnt++; + break; } + pout("%-*s %s\n", TABLEPRINTWIDTH, "OTHER PRESETS:", fixdesc); } } - if (first_preset) - pout("%-*s %s\n", TABLEPRINTWIDTH, "ATTRIBUTE OPTIONS:", "None preset; no -v options are required."); - - // describe firmwarefix - if (fix_firmwarebug) { - const char * fixdesc; - switch (fix_firmwarebug) { - case FIX_SAMSUNG: - fixdesc = "Fixes byte order in some SMART data (same as -F samsung)"; - break; - case FIX_SAMSUNG2: - fixdesc = "Fixes byte order in some SMART data (same as -F samsung2)"; - break; - case FIX_SAMSUNG3: - fixdesc = "Fixes completed self-test reported as in progress (same as -F samsung3)"; - break; - default: - fixdesc = "UNKNOWN"; errcnt++; - break; + else { + // Print USB info + usb_dev_info info; parse_usb_names(dbentry->modelfamily, info); + pout("%-*s %s\n", TABLEPRINTWIDTH, "USB Device:", + (!info.usb_device.empty() ? info.usb_device.c_str() : "[unknown]")); + pout("%-*s %s\n", TABLEPRINTWIDTH, "USB Bridge:", + (!info.usb_bridge.empty() ? info.usb_bridge.c_str() : "[unknown]")); + + if (*dbentry->presets && !parse_usb_type(dbentry->presets, info.usb_type)) { + pout("Syntax error in USB type string \"%s\"\n", dbentry->presets); + errcnt++; } - pout("%-*s %s\n", TABLEPRINTWIDTH, "OTHER PRESETS:", fixdesc); + pout("%-*s %s\n", TABLEPRINTWIDTH, "USB Type", + (!info.usb_type.empty() ? info.usb_type.c_str() : "[unsupported]")); } // Print any special warnings @@ -633,10 +751,19 @@ static bool parse_drive_database(parse_ptr src, drive_database & db, const char break; case 4: if (!token.value.empty()) { - ata_vendor_attr_defs defs; unsigned char fix = 0; - if (!parse_presets(token.value.c_str(), defs, fix)) { - pout("%s(%d): Syntax error in preset option string\n", path, token.line); - ok = false; + if (!is_usb_modelfamily(values[0].c_str())) { + ata_vendor_attr_defs defs; unsigned char fix = 0; + if (!parse_presets(token.value.c_str(), defs, fix)) { + pout("%s(%d): Syntax error in preset option string\n", path, token.line); + ok = false; + } + } + else { + std::string type; + if (!parse_usb_type(token.value.c_str(), type)) { + pout("%s(%d): Syntax error in USB type string\n", path, token.line); + ok = false; + } } } break; diff --git a/smartmontools/knowndrives.h b/smartmontools/knowndrives.h index c695b63df..e69f00300 100644 --- a/smartmontools/knowndrives.h +++ b/smartmontools/knowndrives.h @@ -4,8 +4,8 @@ * Home page of code is: http://smartmontools.sourceforge.net * Address of support mailing list: smartmontools-support@lists.sourceforge.net * - * Copyright (C) 2003-9 Philip Williams, Bruce Allen - * Copyright (C) 2008-9 Christian Franke <smartmontools-support@lists.sourceforge.net> + * Copyright (C) 2003-10 Philip Williams, Bruce Allen + * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,6 +36,18 @@ struct drive_settings { // string. const drive_settings * lookup_drive(const char * model, const char * firmware); +// info returned by lookup_usb_device() +struct usb_dev_info +{ + std::string usb_device; // Device name, empty if unknown + std::string usb_bridge; // USB bridge name, empty if unknown + std::string usb_type; // Type string ('-d' option). +}; + +// Search drivedb for USB device with vendor:product ID. +int lookup_usb_device(int vendor_id, int product_id, int bcd_device, + usb_dev_info & info, usb_dev_info & info2); + // Shows the presets (if any) that are available for the given drive. void show_presets(const ata_identify_device * drive, bool fix_swapped_id); diff --git a/smartmontools/scsiata.cpp b/smartmontools/scsiata.cpp index 52fbdd80d..840d0008f 100644 --- a/smartmontools/scsiata.cpp +++ b/smartmontools/scsiata.cpp @@ -56,6 +56,7 @@ #include "extern.h" #include "scsicmds.h" #include "atacmds.h" // ataReadHDIdentity() +#include "knowndrives.h" // lookup_usb_device() #include "utility.h" #include "dev_interface.h" #include "dev_ata_cmd_set.h" // ata_device_with_command_set @@ -1321,103 +1322,6 @@ ata_device * smart_interface::autodetect_sat_device(scsi_device * scsidev, ///////////////////////////////////////////////////////////////////////////// // USB device type detection -struct usb_id_entry { - int vendor_id, product_id, version; - const char * type; -}; - -const char d_sat[] = "sat"; -const char d_cypress[] = "usbcypress"; -const char d_jmicron[] = "usbjmicron"; -const char d_jmicron_x[] = "usbjmicron,x"; -const char d_sunplus[] = "usbsunplus"; -const char d_unsup[] = "unsupported"; - -// Map USB IDs -> '-d type' string -const usb_id_entry usb_ids[] = { - // Cypress - { 0x04b4, 0x6830, 0x0001, d_unsup }, // Cypress CY7C68300A (AT2) - { 0x04b4, 0x6830, 0x0240, d_cypress }, // Cypress CY7C68300B/C (AT2LP) -//{ 0x04b4, 0x6831, -1, d_cypress }, // Cypress CY7C68310 (ISD-300LP) - // Myson Century - { 0x04cf, 0x8818, 0xb007, d_unsup }, // Myson Century CS8818 - // Samsung - { 0x04e8, 0x5f06, -1, d_sat }, // Samsung Story Station - // Sunplus - { 0x04fc, 0x0c15, 0xf615, d_sunplus }, // SunPlus SPDIF215 - { 0x04fc, 0x0c25, 0x0103, d_sunplus }, // SunPlus SPDIF225 (USB+SATA->SATA) - // Iomega - { 0x059b, 0x0272, -1, d_cypress }, // Iomega LPHD080-0 - { 0x059b, 0x0275, 0x0001, d_unsup }, // Iomega MDHD500-U - // LaCie - { 0x059f, 0x0651, -1, d_unsup }, // LaCie hard disk (FA Porsche design) - { 0x059f, 0x1018, -1, d_sat }, // LaCie hard disk (Neil Poulton design) - { 0x059f, 0x1019, -1, d_jmicron }, // LaCie Desktop Hard Drive - // In-System Design - { 0x05ab, 0x0060, 0x1101, d_cypress }, // In-System/Cypress ISD-300A1 - // Genesys Logic - { 0x05e3, 0x0702, -1, d_unsup }, // Genesys Logic GL881E - { 0x05e3, 0x0718, 0x0041, d_sat }, // Genesys Logic ? (TODO: requires '-T permissive') - // Prolific - { 0x067b, 0x2507, -1, d_unsup }, // Prolific PL2507 (USB->PATA) - { 0x067b, 0x3507, 0x0001, d_unsup }, // Prolific PL3507 (USB+IEE1394->PATA) - // Freecom - { 0x07ab, 0xfc8e, 0x010f, d_sunplus }, // Freecom Hard Drive XS - // Toshiba - { 0x0930, 0x0b03, -1, d_sunplus }, // Toshiba PX1270E-1G16 - { 0x0930, 0x0b09, -1, d_sunplus }, // Toshiba PX1396E-3T01 (similar to Dura Micro 501) - // Seagate - { 0x0bc2, 0x2000, -1, d_sat }, // Seagate FreeAgent Go - { 0x0bc2, 0x2100, -1, d_sat }, // Seagate FreeAgent Go - { 0x0bc2, 0x2101, -1, d_sat }, // Seagate FreeAgent Go - { 0x0bc2, 0x2200, -1, d_sat }, // Seagate FreeAgent Go FW - { 0x0bc2, 0x2300, -1, d_sat }, // Seagate Expansion Portable - { 0x0bc2, 0x3000, -1, d_sat }, // Seagate FreeAgent Desktop - { 0x0bc2, 0x3001, -1, d_sat }, // Seagate FreeAgent Desk - // Dura Micro - { 0x0c0b, 0xb159, 0x0103, d_sunplus }, // Dura Micro 509 - // Maxtor - { 0x0d49, 0x7310, 0x0125, d_sat }, // Maxtor OneTouch 4 - { 0x0d49, 0x7350, 0x0125, d_sat }, // Maxtor OneTouch 4 Mini - { 0x0d49, 0x7410, 0x0122, d_sat }, // Maxtor Basics Desktop - { 0x0d49, 0x7450, 0x0122, d_sat }, // Maxtor Basics Portable - // Western Digital - { 0x1058, 0x0701, 0x0240, d_cypress }, // WD My Passport (IDE) - { 0x1058, 0x0702, 0x0102, d_sat }, // WD My Passport Portable - { 0x1058, 0x0704, 0x0175, d_sat }, // WD My Passport Essential - { 0x1058, 0x0705, 0x0175, d_sat }, // WD My Passport Elite - { 0x1058, 0x070a, 0x1028, d_sat }, // WD My Passport 070A - { 0x1058, 0x0906, 0x0012, d_sat }, // WD My Book ES - { 0x1058, 0x1001, 0x0104, d_sat }, // WD Elements Desktop - { 0x1058, 0x1003, 0x0175, d_sat }, // WD Elements Desktop WDE1UBK... - { 0x1058, 0x1010, 0x0105, d_sat }, // WD Elements - { 0x1058, 0x1100, 0x0165, d_sat }, // WD My Book Essential - { 0x1058, 0x1102, 0x1028, d_sat }, // WD My Book - { 0x1058, 0x1110, 0x1030, d_sat }, // WD My Book Essential - // A-DATA - { 0x125f, 0xa93a, 0x0150, d_cypress }, // A-DATA SH93 - // Initio - { 0x13fd, 0x0540, -1, d_unsup }, // Initio 316000 - { 0x13fd, 0x1240, 0x0104, d_sat }, // Initio ? (USB->SATA) - { 0x13fd, 0x1340, 0x0208, d_sat }, // Initio ? (USB+SATA->SATA) - // JMicron - { 0x152d, 0x2329, 0x0100, d_jmicron }, // JMicron JM20329 (USB->SATA) - { 0x152d, 0x2336, 0x0100, d_jmicron_x},// JMicron JM20336 (USB+SATA->SATA, USB->2xSATA) - { 0x152d, 0x2338, 0x0100, d_jmicron }, // JMicron JM20337/8 (USB->SATA+PATA, USB+SATA->PATA) - { 0x152d, 0x2339, 0x0100, d_jmicron_x},// JMicron JM20339 (USB->SATA) - // Verbatim - { 0x18a5, 0x0215, 0x0001, d_sat }, // Verbatim FW/USB160 - Oxford OXUF934SSA-LQAG (USB+IEE1394->SATA) - // SunplusIT - { 0x1bcf, 0x0c31, -1, d_sunplus }, // SunplusIT - // Hitachi/SimpleTech - { 0x4971, 0xce17, -1, d_jmicron }, // Hitachi/SimpleTech 1TB - // OnSpec - { 0x55aa, 0x2b00, 0x0100, d_unsup } // OnSpec ? (USB->PATA) -}; - -const unsigned num_usb_ids = sizeof(usb_ids)/sizeof(usb_ids[0]); - - // Format USB ID for error messages static std::string format_usb_id(int vendor_id, int product_id, int version) { @@ -1431,41 +1335,31 @@ static std::string format_usb_id(int vendor_id, int product_id, int version) const char * smart_interface::get_usb_dev_type_by_id(int vendor_id, int product_id, int version /*= -1*/) { - const usb_id_entry * entry = 0; - bool state = false; - - for (unsigned i = 0; i < num_usb_ids; i++) { - const usb_id_entry & e = usb_ids[i]; - if (!(vendor_id == e.vendor_id && product_id == e.product_id)) - continue; - - // If two entries with same vendor:product ID have different - // types, use version (if provided by OS) to select entry. - bool s = (version >= 0 && version == e.version); - if (entry) { - if (s <= state) { - if (s == state && e.type != entry->type) { - set_err(EINVAL, "USB bridge %s type is ambiguous: '%s' or '%s'", - format_usb_id(vendor_id, product_id, version).c_str(), - e.type, entry->type); - return 0; - } - continue; - } - } - state = s; - entry = &e; - } + usb_dev_info info, info2; + int n = lookup_usb_device(vendor_id, product_id, version, info, info2); - if (!entry) { + if (n <= 0) { set_err(EINVAL, "Unknown USB bridge %s", format_usb_id(vendor_id, product_id, version).c_str()); return 0; } - if (entry->type == d_unsup) { + + if (n > 1) { + set_err(EINVAL, "USB bridge %s type is ambiguous: '%s' or '%s'", + format_usb_id(vendor_id, product_id, version).c_str(), + (!info.usb_type.empty() ? info.usb_type.c_str() : "[unsupported]"), + (!info2.usb_type.empty() ? info2.usb_type.c_str() : "[unsupported]")); + return 0; + } + + if (info.usb_type.empty()) { set_err(ENOSYS, "Unsupported USB bridge %s", format_usb_id(vendor_id, product_id, version).c_str()); return 0; } - return entry->type; + + // TODO: change return type to std::string + static std::string type; + type = info.usb_type; + return type.c_str(); } diff --git a/smartmontools/smartctl.8.in b/smartmontools/smartctl.8.in index a2245cc82..1f1076aab 100644 --- a/smartmontools/smartctl.8.in +++ b/smartmontools/smartctl.8.in @@ -1339,6 +1339,14 @@ Example: "", // No warning. "" // No options preset. }, + /* USB ID entry: */ + { + "USB: Device; Bridge", // Info about USB device and bridge name. + "0x1234:0xabcd", // Regular expression to match vendor:product ID. + "0x0101", // Regular expression to match bcdDevice. + "", // Not used. + "\-d sat" // String with device type option. + }, /* ... */ .fi -- GitLab