smartmontools SVN Rev 3317
Utility to control and monitor storage systems with "S.M.A.R.T."
dev_legacy.cpp
Go to the documentation of this file.
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 }