|
smartmontools SVN Rev 3317
Utility to control and monitor storage systems with "S.M.A.R.T."
|
00001 /* 00002 * dev_legacy.cpp 00003 * 00004 * Home page of code is: http://smartmontools.sourceforge.net 00005 * 00006 * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net> 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2, or (at your option) 00011 * any later version. 00012 * 00013 * You should have received a copy of the GNU General Public License 00014 * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. 00015 * 00016 */ 00017 00018 #include "config.h" 00019 #include "int64.h" 00020 #include "utility.h" 00021 #include "atacmds.h" 00022 #include "scsicmds.h" 00023 #include "dev_interface.h" 00024 #include "dev_ata_cmd_set.h" 00025 00026 #include <errno.h> 00027 00028 const char * dev_legacy_cpp_cvsid = "$Id: dev_legacy.cpp 3263 2011-02-20 18:32:56Z chrfranke $" 00029 DEV_INTERFACE_H_CVSID; 00030 00031 ///////////////////////////////////////////////////////////////////////////// 00032 00033 // Legacy interface declarations (now commented out globally): 00034 00035 // from utility.h: 00036 int guess_device_type(const char * dev_name); 00037 int make_device_names (char ***devlist, const char* name); 00038 int deviceopen(const char *pathname, char *type); 00039 int deviceclose(int fd); 00040 00041 // from atacmds.h: 00042 int ata_command_interface(int device, smart_command_set command, int select, char *data); 00043 00044 // from scsicmds.h: 00045 int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report); 00046 00047 // from smartctl.h: 00048 void print_smartctl_examples(); 00049 00050 ///////////////////////////////////////////////////////////////////////////// 00051 00052 namespace os { // No need to publish anything, name provided for Doxygen 00053 00054 ///////////////////////////////////////////////////////////////////////////// 00055 /// Implement shared open/close routines with old functions. 00056 00057 class legacy_smart_device 00058 : virtual public /*implements*/ smart_device 00059 { 00060 public: 00061 explicit legacy_smart_device(const char * mode) 00062 : smart_device(never_called), 00063 m_fd(-1), m_mode(mode) { } 00064 00065 virtual ~legacy_smart_device() throw(); 00066 00067 virtual bool is_open() const; 00068 00069 virtual bool open(); 00070 00071 virtual bool close(); 00072 00073 protected: 00074 /// Return filedesc for derived classes. 00075 int get_fd() const 00076 { return m_fd; } 00077 00078 private: 00079 int m_fd; ///< filedesc, -1 if not open. 00080 const char * m_mode; ///< Mode string for deviceopen(). 00081 }; 00082 00083 00084 legacy_smart_device::~legacy_smart_device() throw() 00085 { 00086 if (m_fd >= 0) 00087 ::deviceclose(m_fd); 00088 } 00089 00090 bool legacy_smart_device::is_open() const 00091 { 00092 return (m_fd >= 0); 00093 } 00094 00095 bool legacy_smart_device::open() 00096 { 00097 m_fd = ::deviceopen(get_dev_name(), const_cast<char*>(m_mode)); 00098 if (m_fd < 0) { 00099 set_err((errno==ENOENT || errno==ENOTDIR) ? ENODEV : errno); 00100 return false; 00101 } 00102 return true; 00103 } 00104 00105 bool legacy_smart_device::close() 00106 { 00107 int fd = m_fd; m_fd = -1; 00108 if (::deviceclose(fd) < 0) { 00109 set_err(errno); 00110 return false; 00111 } 00112 return true; 00113 } 00114 00115 ///////////////////////////////////////////////////////////////////////////// 00116 /// Implement standard ATA support with old functions 00117 00118 class legacy_ata_device 00119 : public /*implements*/ ata_device_with_command_set, 00120 public /*extends*/ legacy_smart_device 00121 { 00122 public: 00123 legacy_ata_device(smart_interface * intf, const char * dev_name, const char * req_type); 00124 00125 protected: 00126 virtual int ata_command_interface(smart_command_set command, int select, char * data); 00127 }; 00128 00129 legacy_ata_device::legacy_ata_device(smart_interface * intf, const char * dev_name, const char * req_type) 00130 : smart_device(intf, dev_name, "ata", req_type), 00131 legacy_smart_device("ATA") 00132 { 00133 } 00134 00135 int legacy_ata_device::ata_command_interface(smart_command_set command, int select, char * data) 00136 { 00137 return ::ata_command_interface(get_fd(), command, select, data); 00138 } 00139 00140 00141 ///////////////////////////////////////////////////////////////////////////// 00142 /// Implement standard SCSI support with old functions 00143 00144 class legacy_scsi_device 00145 : public /*implements*/ scsi_device, 00146 public /*extends*/ legacy_smart_device 00147 { 00148 public: 00149 legacy_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type); 00150 00151 virtual smart_device * autodetect_open(); 00152 00153 virtual bool scsi_pass_through(scsi_cmnd_io * iop); 00154 }; 00155 00156 legacy_scsi_device::legacy_scsi_device(smart_interface * intf, 00157 const char * dev_name, const char * req_type) 00158 : smart_device(intf, dev_name, "scsi", req_type), 00159 legacy_smart_device("SCSI") 00160 { 00161 } 00162 00163 bool legacy_scsi_device::scsi_pass_through(scsi_cmnd_io * iop) 00164 { 00165 int status = ::do_scsi_cmnd_io(get_fd(), iop, scsi_debugmode); 00166 if (status < 0) { 00167 set_err(-status); 00168 return false; 00169 } 00170 return true; 00171 } 00172 00173 00174 ///////////////////////////////////////////////////////////////////////////// 00175 /// SCSI open with autodetection support 00176 00177 smart_device * legacy_scsi_device::autodetect_open() 00178 { 00179 // Open device 00180 if (!open()) 00181 return this; 00182 00183 // No Autodetection if device type was specified by user 00184 if (*get_req_type()) 00185 return this; 00186 00187 // The code below is based on smartd.cpp:SCSIFilterKnown() 00188 00189 // Get INQUIRY 00190 unsigned char req_buff[64] = {0, }; 00191 int req_len = 36; 00192 if (scsiStdInquiry(this, req_buff, req_len)) { 00193 // Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices 00194 // watch this spot ... other devices could lock up here 00195 req_len = 64; 00196 if (scsiStdInquiry(this, req_buff, req_len)) { 00197 // device doesn't like INQUIRY commands 00198 close(); 00199 set_err(EIO, "INQUIRY failed"); 00200 return this; 00201 } 00202 } 00203 00204 int avail_len = req_buff[4] + 5; 00205 int len = (avail_len < req_len ? avail_len : req_len); 00206 if (len < 36) 00207 return this; 00208 00209 // Use INQUIRY to detect type 00210 00211 // SAT or USB ? 00212 { 00213 smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len); 00214 if (newdev) 00215 // NOTE: 'this' is now owned by '*newdev' 00216 return newdev; 00217 } 00218 00219 // Nothing special found 00220 return this; 00221 } 00222 00223 00224 ///////////////////////////////////////////////////////////////////////////// 00225 /// Implement platform interface with old functions. 00226 00227 class legacy_smart_interface 00228 : public /*implements*/ smart_interface 00229 { 00230 public: 00231 virtual std::string get_app_examples(const char * appname); 00232 00233 virtual bool scan_smart_devices(smart_device_list & devlist, const char * type, 00234 const char * pattern = 0); 00235 00236 protected: 00237 virtual ata_device * get_ata_device(const char * name, const char * type); 00238 00239 virtual scsi_device * get_scsi_device(const char * name, const char * type); 00240 00241 virtual smart_device * autodetect_smart_device(const char * name); 00242 }; 00243 00244 00245 ////////////////////////////////////////////////////////////////////// 00246 00247 std::string legacy_smart_interface::get_app_examples(const char * appname) 00248 { 00249 if (!strcmp(appname, "smartctl")) 00250 ::print_smartctl_examples(); // this prints to stdout ... 00251 return ""; // ... so don't print again. 00252 } 00253 00254 ata_device * legacy_smart_interface::get_ata_device(const char * name, const char * type) 00255 { 00256 return new legacy_ata_device(this, name, type); 00257 } 00258 00259 scsi_device * legacy_smart_interface::get_scsi_device(const char * name, const char * type) 00260 { 00261 return new legacy_scsi_device(this, name, type); 00262 } 00263 00264 00265 smart_device * legacy_smart_interface::autodetect_smart_device(const char * name) 00266 { 00267 switch (::guess_device_type(name)) { 00268 case CONTROLLER_ATA : return new legacy_ata_device(this, name, ""); 00269 case CONTROLLER_SCSI: return new legacy_scsi_device(this, name, ""); 00270 } 00271 // TODO: Test autodetect device here 00272 return 0; 00273 } 00274 00275 00276 static void free_devnames(char * * devnames, int numdevs) 00277 { 00278 static const char version[] = "$Id: dev_legacy.cpp 3263 2011-02-20 18:32:56Z chrfranke $"; 00279 for (int i = 0; i < numdevs; i++) 00280 FreeNonZero(devnames[i], -1,__LINE__, version); 00281 FreeNonZero(devnames, (sizeof (char*) * numdevs),__LINE__, version); 00282 } 00283 00284 bool legacy_smart_interface::scan_smart_devices(smart_device_list & devlist, 00285 const char * type, const char * pattern /*= 0*/) 00286 { 00287 if (pattern) { 00288 set_err(EINVAL, "DEVICESCAN with pattern not implemented yet"); 00289 return false; 00290 } 00291 00292 // Make namelists 00293 char * * atanames = 0; int numata = 0; 00294 if (!type || !strcmp(type, "ata")) { 00295 numata = ::make_device_names(&atanames, "ATA"); 00296 if (numata < 0) { 00297 set_err(ENOMEM); 00298 return false; 00299 } 00300 } 00301 00302 char * * scsinames = 0; int numscsi = 0; 00303 if (!type || !strcmp(type, "scsi")) { 00304 numscsi = ::make_device_names(&scsinames, "SCSI"); 00305 if (numscsi < 0) { 00306 free_devnames(atanames, numata); 00307 set_err(ENOMEM); 00308 return false; 00309 } 00310 } 00311 00312 // Add to devlist 00313 int i; 00314 if (!type) 00315 type=""; 00316 for (i = 0; i < numata; i++) { 00317 ata_device * atadev = get_ata_device(atanames[i], type); 00318 if (atadev) 00319 devlist.push_back(atadev); 00320 } 00321 free_devnames(atanames, numata); 00322 00323 for (i = 0; i < numscsi; i++) { 00324 scsi_device * scsidev = get_scsi_device(scsinames[i], type); 00325 if (scsidev) 00326 devlist.push_back(scsidev); 00327 } 00328 free_devnames(scsinames, numscsi); 00329 return true; 00330 } 00331 00332 } // namespace 00333 00334 00335 ///////////////////////////////////////////////////////////////////////////// 00336 /// Initialize platform interface and register with smi() 00337 00338 void smart_interface::init() 00339 { 00340 static os::legacy_smart_interface the_interface; 00341 smart_interface::set(&the_interface); 00342 }
1.7.4