]> git.proxmox.com Git - mirror_smartmontools-debian.git/blobdiff - os_linux.cpp
Stop passing arguments to dh_installinit
[mirror_smartmontools-debian.git] / os_linux.cpp
index dbdab1f4be3e3ee9ffdc214198680dec4e8ea3e4..6374a5b6b255484f143b19812da382208df56c49 100644 (file)
@@ -1,20 +1,27 @@
 /*
  *  os_linux.cpp
  *
- * Home page of code is: http://smartmontools.sourceforge.net
+ * Home page of code is: http://www.smartmontools.org
  *
- * Copyright (C) 2003-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2003-11 Bruce Allen
  * Copyright (C) 2003-11 Doug Gilbert <dgilbert@interlog.com>
- * Copyright (C) 2008-12 Hank Wu <hank@areca.com.tw>
- * Copyright (C) 2008    Oliver Bock <brevilo@users.sourceforge.net>
- * Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net>
- * Copyright (C) 2008    Jordan Hargrave <jordan_hargrave@dell.com>
+ * Copyright (C) 2008-15 Christian Franke
  *
- *  Parts of this file are derived from code that was
+ * Original AACRaid code:
+ *  Copyright (C) 2014    Raghava Aditya <raghava.aditya@pmcs.com>
+ *
+ * Original Areca code:
+ *  Copyright (C) 2008-12 Hank Wu <hank@areca.com.tw>
+ *  Copyright (C) 2008    Oliver Bock <brevilo@users.sourceforge.net>
+ *
+ * Original MegaRAID code:
+ *  Copyright (C) 2008    Jordan Hargrave <jordan_hargrave@dell.com>
+ *
+ * 3ware code was derived from code that was:
  *
  *  Written By: Adam Radford <linux@3ware.com>
  *  Modifications By: Joel Jacobson <linux@3ware.com>
- *                   Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *                    Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  *                    Brad Strand <linux@3ware.com>
  *
  *  Copyright (C) 1999-2003 3ware Inc.
@@ -80,6 +87,7 @@
 #include "utility.h"
 #include "cciss.h"
 #include "megaraid.h"
+#include "aacraid.h"
 
 #include "dev_interface.h"
 #include "dev_ata_cmd_set.h"
@@ -91,7 +99,7 @@
 
 #define ARGUSED(x) ((void)(x))
 
-const char * os_linux_cpp_cvsid = "$Id: os_linux.cpp 3824 2013-07-05 10:40:38Z samm2 $"
+const char * os_linux_cpp_cvsid = "$Id: os_linux.cpp 4157 2015-10-20 16:03:57Z chrfranke $"
   OS_LINUX_H_CVSID;
 extern unsigned char failuretest_permissive;
 
@@ -186,11 +194,11 @@ bool linux_smart_device::close()
 // examples for smartctl
 static const char  smartctl_examples[] =
                  "=================================================== SMARTCTL EXAMPLES =====\n\n"
-                 "  smartctl --all /dev/hda                    (Prints all SMART information)\n\n"
-                 "  smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n"
+                 "  smartctl --all /dev/sda                    (Prints all SMART information)\n\n"
+                 "  smartctl --smart=on --offlineauto=on --saveauto=on /dev/sda\n"
                  "                                              (Enables SMART on first disk)\n\n"
-                 "  smartctl --test=long /dev/hda          (Executes extended disk self-test)\n\n"
-                 "  smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n"
+                 "  smartctl --test=long /dev/sda          (Executes extended disk self-test)\n\n"
+                 "  smartctl --attributes --log=selftest --quietmode=errorsonly /dev/sda\n"
                  "                                      (Prints Self-Test & Attribute errors)\n"
                  "  smartctl --all --device=3ware,2 /dev/sda\n"
                  "  smartctl --all --device=3ware,2 /dev/twe0\n"
@@ -348,7 +356,6 @@ int linux_ata_device::ata_command_interface(smart_command_set command, int selec
     unsigned char task[sizeof(ide_task_request_t)+512];
     ide_task_request_t *reqtask=(ide_task_request_t *) task;
     task_struct_t      *taskfile=(task_struct_t *) reqtask->io_ports;
-    int retval;
 
     memset(task,      0, sizeof(task));
 
@@ -369,8 +376,8 @@ int linux_ata_device::ata_command_interface(smart_command_set command, int selec
     // copy user data into the task request structure
     memcpy(task+sizeof(ide_task_request_t), data, 512);
 
-    if ((retval=ioctl(get_fd(), HDIO_DRIVE_TASKFILE, task))) {
-      if (retval==-EINVAL)
+    if (ioctl(get_fd(), HDIO_DRIVE_TASKFILE, task)) {
+      if (errno==-EINVAL)
         pout("Kernel lacks HDIO_DRIVE_TASKFILE support; compile kernel with CONFIG_IDE_TASKFILE_IO set\n");
       return -1;
     }
@@ -380,8 +387,6 @@ int linux_ata_device::ata_command_interface(smart_command_set command, int selec
   // There are two different types of ioctls().  The HDIO_DRIVE_TASK
   // one is this:
   if (command==STATUS_CHECK || command==AUTOSAVE || command==AUTO_OFFLINE){
-    int retval;
-
     // NOT DOCUMENTED in /usr/src/linux/include/linux/hdreg.h. You
     // have to read the IDE driver source code.  Sigh.
     // buff[0]: ATA COMMAND CODE REGISTER
@@ -397,8 +402,8 @@ int linux_ata_device::ata_command_interface(smart_command_set command, int selec
     buff[4]=normal_lo;
     buff[5]=normal_hi;
 
-    if ((retval=ioctl(get_fd(), HDIO_DRIVE_TASK, buff))) {
-      if (retval==-EINVAL) {
+    if (ioctl(get_fd(), HDIO_DRIVE_TASK, buff)) {
+      if (errno==-EINVAL) {
         pout("Error SMART Status command via HDIO_DRIVE_TASK failed");
         pout("Rebuild older linux 2.2 kernels with HDIO_DRIVE_TASK support added\n");
       }
@@ -859,6 +864,243 @@ bool linux_scsi_device::scsi_pass_through(scsi_cmnd_io * iop)
   return true;
 }
 
+/////////////////////////////////////////////////////////////////////////////
+/// PMC AacRAID support
+
+class linux_aacraid_device
+:public   scsi_device,
+ public /*extends */   linux_smart_device
+{
+public:
+  linux_aacraid_device(smart_interface *intf, const char *dev_name,
+    unsigned int host, unsigned int channel, unsigned int device);
+
+  virtual ~linux_aacraid_device() throw();
+
+  virtual bool open();
+
+  virtual bool scsi_pass_through(scsi_cmnd_io *iop);
+
+private:
+  //Device Host number
+  int aHost;
+
+  //Channel(Lun) of the device
+  int aLun;
+
+  //Id of the device
+  int aId;
+
+};
+
+linux_aacraid_device::linux_aacraid_device(smart_interface *intf,
+  const char *dev_name, unsigned int host, unsigned int channel, unsigned int device)
+   : smart_device(intf,dev_name,"aacraid","aacraid"),
+     linux_smart_device(O_RDWR|O_NONBLOCK),
+     aHost(host), aLun(channel), aId(device)
+{
+  set_info().info_name = strprintf("%s [aacraid_disk_%02d_%02d_%d]",dev_name,aHost,aLun,aId);
+  set_info().dev_type  = strprintf("aacraid,%d,%d,%d",aHost,aLun,aId);
+}
+
+linux_aacraid_device::~linux_aacraid_device() throw()
+{
+}
+
+bool linux_aacraid_device::open()
+{
+  //Create the character device name based on the host number
+  //Required for get stats from disks connected to different controllers
+  char dev_name[128];
+  snprintf(dev_name, sizeof(dev_name), "/dev/aac%d", aHost);
+
+  //Initial open of dev name to check if it exsists
+  int afd = ::open(dev_name,O_RDWR);
+
+  if(afd < 0 && errno == ENOENT) {
+
+    FILE *fp = fopen("/proc/devices","r");
+    if(NULL == fp)
+      return set_err(errno,"cannot open /proc/devices:%s",
+                     strerror(errno));
+
+    char line[256];
+    int mjr = -1;
+
+    while(fgets(line,sizeof(line),fp) !=NULL) {
+      int nc = -1;
+      if(sscanf(line,"%d aac%n",&mjr,&nc) == 1
+                && nc > 0 && '\n' == line[nc])
+        break;
+      mjr = -1;
+    }
+
+    //work with /proc/devices is done
+    fclose(fp);
+
+    if (mjr < 0)
+      return set_err(ENOENT, "aac entry not found in /proc/devices");
+
+    //Create misc device file in /dev/ used for communication with driver
+    if(mknod(dev_name,S_IFCHR,makedev(mjr,aHost)))
+      return set_err(errno,"cannot create %s:%s",dev_name,strerror(errno));
+
+    afd = ::open(dev_name,O_RDWR);
+  }
+
+  if(afd < 0)
+    return set_err(errno,"cannot open %s:%s",dev_name,strerror(errno));
+
+  set_fd(afd);
+  return true;
+}
+
+bool linux_aacraid_device::scsi_pass_through(scsi_cmnd_io *iop)
+{
+  int report = scsi_debugmode;
+
+  if (report > 0) {
+    int k, j;
+    const unsigned char * ucp = iop->cmnd;
+    const char * np;
+    char buff[256];
+    const int sz = (int)sizeof(buff);
+
+    np = scsi_get_opcode_name(ucp[0]);
+    j  = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
+    for (k = 0; k < (int)iop->cmnd_len; ++k)
+      j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
+      if ((report > 1) &&
+        (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
+        int trunc = (iop->dxfer_len > 256) ? 1 : 0;
+
+        j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n  Outgoing "
+                      "data, len=%d%s:\n", (int)iop->dxfer_len,
+                      (trunc ? " [only first 256 bytes shown]" : ""));
+        dStrHex((const char *)iop->dxferp,
+               (trunc ? 256 : iop->dxfer_len) , 1);
+    }
+    else
+      j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
+
+    pout("%s", buff);
+  }
+
+
+  //return test commands
+  if (iop->cmnd[0] == 0x00)
+    return true;
+
+  user_aac_reply *pReply;
+
+  #ifdef ENVIRONMENT64
+    // Create user 64 bit request
+    user_aac_srb64  *pSrb;
+    uint8_t aBuff[sizeof(user_aac_srb64) + sizeof(user_aac_reply)] = {0,};
+
+    pSrb    = (user_aac_srb64*)aBuff;
+    pSrb->count = sizeof(user_aac_srb64) - sizeof(user_sgentry64);
+
+ #elif defined(ENVIRONMENT32)
+    //Create user 32 bit request
+    user_aac_srb32  *pSrb;
+    uint8_t aBuff[sizeof(user_aac_srb32) + sizeof(user_aac_reply)] = {0,};
+
+    pSrb    = (user_aac_srb32*)aBuff;
+    pSrb->count = sizeof(user_aac_srb32) - sizeof(user_sgentry32);
+ #endif
+
+  pSrb->function = SRB_FUNCTION_EXECUTE_SCSI;
+  //channel is 0 always
+  pSrb->channel  = 0;
+  pSrb->id       = aId;
+  pSrb->lun      = aLun;
+  pSrb->timeout  = 0;
+
+  pSrb->retry_limit = 0;
+  pSrb->cdb_size    = iop->cmnd_len;
+
+  switch(iop->dxfer_dir) {
+    case DXFER_NONE:
+      pSrb->flags = SRB_NoDataXfer;
+      break;
+    case DXFER_FROM_DEVICE:
+      pSrb->flags = SRB_DataIn;
+      break;
+    case DXFER_TO_DEVICE:
+      pSrb->flags = SRB_DataOut;
+      break;
+    default:
+      pout("aacraid: bad dxfer_dir\n");
+      return set_err(EINVAL, "aacraid: bad dxfer_dir\n");
+  }
+
+  if(iop->dxfer_len > 0) {
+
+    #ifdef ENVIRONMENT64
+      pSrb->sg64.count = 1;
+      pSrb->sg64.sg64[0].addr64.lo32 = ((intptr_t)iop->dxferp) &
+                                         0x00000000ffffffff;
+      pSrb->sg64.sg64[0].addr64.hi32 = ((intptr_t)iop->dxferp) >> 32;
+
+      pSrb->sg64.sg64[0].length = (uint32_t)iop->dxfer_len;
+      pSrb->count += pSrb->sg64.count * sizeof(user_sgentry64);
+    #elif defined(ENVIRONMENT32)
+      pSrb->sg32.count = 1;
+      pSrb->sg32.sg32[0].addr32 = (intptr_t)iop->dxferp;
+
+      pSrb->sg32.sg32[0].length = (uint32_t)iop->dxfer_len;
+      pSrb->count += pSrb->sg32.count * sizeof(user_sgentry32);
+    #endif
+
+  }
+
+  pReply  = (user_aac_reply*)(aBuff+pSrb->count);
+
+  memcpy(pSrb->cdb,iop->cmnd,iop->cmnd_len);
+
+  int rc = 0;
+  errno = 0;
+  rc = ioctl(get_fd(),FSACTL_SEND_RAW_SRB,pSrb);
+
+  if (rc != 0)
+    return set_err(errno, "aacraid send_raw_srb: %d.%d = %s",
+                  aLun, aId, strerror(errno));
+
+/* see kernel aacraid.h and MSDN SCSI_REQUEST_BLOCK documentation */
+#define SRB_STATUS_SUCCESS            0x1
+#define SRB_STATUS_ERROR              0x4
+#define SRB_STATUS_NO_DEVICE         0x08
+#define SRB_STATUS_SELECTION_TIMEOUT 0x0a
+#define SRB_STATUS_AUTOSENSE_VALID   0x80
+
+  iop->scsi_status = pReply->scsi_status;
+
+  if (pReply->srb_status == (SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_ERROR)
+      && iop->scsi_status == SCSI_STATUS_CHECK_CONDITION) {
+    memcpy(iop->sensep, pReply->sense_data, pReply->sense_data_size);
+    iop->resp_sense_len = pReply->sense_data_size;
+    return true; /* request completed with sense data */
+  }
+
+  switch (pReply->srb_status & 0x3f) {
+
+    case SRB_STATUS_SUCCESS:
+      return true; /* request completed successfully */
+
+    case SRB_STATUS_NO_DEVICE:
+      return set_err(EIO, "aacraid: Device %d %d does not exist", aLun, aId);
+
+    case SRB_STATUS_SELECTION_TIMEOUT:
+      return set_err(EIO, "aacraid: Device %d %d not responding", aLun, aId);
+
+    default:
+      return set_err(EIO, "aacraid result: %d.%d = 0x%x",
+                    aLun, aId, pReply->srb_status);
+  }
+}
+
+
 /////////////////////////////////////////////////////////////////////////////
 /// LSI MegaRAID support
 
@@ -957,7 +1199,7 @@ bool linux_megaraid_device::open()
   int   mjr;
   int report = scsi_debugmode;
 
-  if(sscanf(get_dev_name(),"/dev/bus/%d", &m_hba) == 0) {
+  if (sscanf(get_dev_name(), "/dev/bus/%u", &m_hba) == 0) {
     if (!linux_smart_device::open())
       return false;
     /* Get device HBA */
@@ -1080,7 +1322,6 @@ bool linux_megaraid_device::megasas_cmd(int cdbLen, void *cdb,
 {
   struct megasas_pthru_frame   *pthru;
   struct megasas_iocpacket     uio;
-  int rc;
 
   memset(&uio, 0, sizeof(uio));
   pthru = &uio.frame.pthru;
@@ -1122,9 +1363,8 @@ bool linux_megaraid_device::megasas_cmd(int cdbLen, void *cdb,
     uio.sgl[0].iov_len = dataLen;
   }
 
-  rc = 0;
   errno = 0;
-  rc = ioctl(m_fd, MEGASAS_IOC_FIRMWARE, &uio);
+  int rc = ioctl(m_fd, MEGASAS_IOC_FIRMWARE, &uio);
   if (pthru->cmd_status || rc != 0) {
     if (pthru->cmd_status == 12) {
       return set_err(EIO, "megasas_cmd: Device %d does not exist\n", m_disknum);
@@ -1746,10 +1986,8 @@ linux_areca_ata_device::linux_areca_ata_device(smart_interface * intf, const cha
 
 smart_device * linux_areca_ata_device::autodetect_open()
 {
-  int is_ata = 1;
-
   // autodetect device type
-  is_ata = arcmsr_get_dev_type();
+  int is_ata = arcmsr_get_dev_type();
   if(is_ata < 0)
   {
     set_err(EIO);
@@ -2456,8 +2694,7 @@ std::string linux_smart_interface::get_app_examples(const char * appname)
 }
 
 // we are going to take advantage of the fact that Linux's devfs will only
-// have device entries for devices that exist.  So if we get the equivalent of
-// ls /dev/hd[a-t], we have all the ATA devices on the system
+// have device entries for devices that exist.
 bool linux_smart_interface::get_dev_list(smart_device_list & devlist,
   const char * pattern, bool scan_ata, bool scan_scsi,
   const char * req_type, bool autodetect)
@@ -2488,7 +2725,7 @@ bool linux_smart_interface::get_dev_list(smart_device_list & devlist,
   }
 
   // did we find too many paths?
-  const int max_pathc = 32;
+  const int max_pathc = 1024;
   int n = (int)globbuf.gl_pathc;
   if (n > max_pathc) {
     pout("glob(3) found %d > MAX=%d devices matching pattern %s: ignoring %d paths\n",
@@ -2580,20 +2817,19 @@ bool linux_smart_interface::get_dev_megasas(smart_device_list & devlist)
     return false;
 
   // getting bus numbers with megasas devices
-  struct dirent *ep;
-  unsigned int host_no = 0;
-  char sysfsdir[256];
-
-  /* we are using sysfs to get list of all scsi hosts */
+  // we are using sysfs to get list of all scsi hosts
   DIR * dp = opendir ("/sys/class/scsi_host/");
   if (dp != NULL)
   {
+    struct dirent *ep;
     while ((ep = readdir (dp)) != NULL) {
-      if (!sscanf(ep->d_name, "host%d", &host_no)) 
+      unsigned int host_no = 0;
+      if (!sscanf(ep->d_name, "host%u", &host_no))
         continue;
       /* proc_name should be megaraid_sas */
+      char sysfsdir[256];
       snprintf(sysfsdir, sizeof(sysfsdir) - 1,
-        "/sys/class/scsi_host/host%d/proc_name", host_no);
+        "/sys/class/scsi_host/host%u/proc_name", host_no);
       if((fp = fopen(sysfsdir, "r")) == NULL)
         continue;
       if(fgets(line, sizeof(line), fp) != NULL && !strncmp(line,"megaraid_sas",12)) {
@@ -2703,6 +2939,7 @@ linux_smart_interface::megasas_dcmd_cmd(int bus_no, uint32_t opcode, void *buf,
   }
 
   int r = ioctl(fd, MEGASAS_IOC_FIRMWARE, &ioc);
+  ::close(fd);
   if (r < 0) {
     return (r);
   }
@@ -2727,7 +2964,7 @@ linux_smart_interface::megasas_pd_add_list(int bus_no, smart_device_list & devli
   */
   megasas_pd_list * list = 0;
   for (unsigned list_size = 1024; ; ) {
-    list = (megasas_pd_list *)realloc(list, list_size);
+    list = reinterpret_cast<megasas_pd_list *>(realloc(list, list_size));
     if (!list)
       throw std::bad_alloc();
     bzero(list, list_size);
@@ -2939,12 +3176,22 @@ smart_device * linux_smart_interface::get_custom_smart_device(const char * name,
   if (sscanf(type, "megaraid,%d", &disknum) == 1) {
     return new linux_megaraid_device(this, name, 0, disknum);
   }
+
+  //aacraid?
+  unsigned host, chan, device;
+  if (sscanf(type, "aacraid,%u,%u,%u", &host, &chan, &device) == 3) {
+    //return new linux_aacraid_device(this,name,channel,device);
+    return get_sat_device("sat,auto",
+      new linux_aacraid_device(this, name, host, chan, device));
+
+  }
+
   return 0;
 }
 
 std::string linux_smart_interface::get_valid_custom_dev_types_str()
 {
-  return "marvell, areca,N/E, 3ware,N, hpt,L/M/N, megaraid,N"
+  return "marvell, areca,N/E, 3ware,N, hpt,L/M/N, megaraid,N, aacraid,H,L,ID"
 #ifdef HAVE_LINUX_CCISS_IOCTL_H
                                               ", cciss,N"
 #endif