Diff for /embedaddon/smartmontools/os_linux.cpp between versions 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2012/10/09 09:36:45 version 1.1.1.3, 2013/07/22 01:17:35
Line 65 Line 65
 #include <stddef.h>  // for offsetof()  #include <stddef.h>  // for offsetof()
 #include <sys/uio.h>  #include <sys/uio.h>
 #include <sys/types.h>  #include <sys/types.h>
   #include <dirent.h>
 #ifndef makedev // old versions of types.h do not include sysmacros.h  #ifndef makedev // old versions of types.h do not include sysmacros.h
 #include <sys/sysmacros.h>  #include <sys/sysmacros.h>
 #endif  #endif
Line 82 Line 83
   
 #include "dev_interface.h"  #include "dev_interface.h"
 #include "dev_ata_cmd_set.h"  #include "dev_ata_cmd_set.h"
   #include "dev_areca.h"
   
 #ifndef ENOTSUP  #ifndef ENOTSUP
 #define ENOTSUP ENOSYS  #define ENOTSUP ENOSYS
Line 91 Line 93
   
 const char * os_linux_cpp_cvsid = "$Id$"  const char * os_linux_cpp_cvsid = "$Id$"
   OS_LINUX_H_CVSID;    OS_LINUX_H_CVSID;
   extern unsigned char failuretest_permissive;
   
   
 namespace os_linux { // No need to publish anything, name provided for Doxygen  namespace os_linux { // No need to publish anything, name provided for Doxygen
   
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
Line 121  class linux_smart_device (protected) Line 123  class linux_smart_device (protected)
   int get_fd() const    int get_fd() const
     { return m_fd; }      { return m_fd; }
   
     void set_fd(int fd)
       { m_fd = fd; }
   
 private:  private:
   int m_fd; ///< filedesc, -1 if not open.    int m_fd; ///< filedesc, -1 if not open.
   int m_flags; ///< Flags for ::open()    int m_flags; ///< Flags for ::open()
   int m_retry_flags; ///< Flags to retry ::open(), -1 if no retry    int m_retry_flags; ///< Flags to retry ::open(), -1 if no retry
 };  };
   
   
 linux_smart_device::~linux_smart_device() throw()  linux_smart_device::~linux_smart_device() throw()
 {  {
   if (m_fd >= 0)    if (m_fd >= 0)
Line 201  static const char  smartctl_examples[] = Line 205  static const char  smartctl_examples[] =
                   "           on Areca RAID controller)\n"                    "           on Areca RAID controller)\n"
   ;    ;
   
   
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
 /// Linux ATA support  /// Linux ATA support
   
Line 242  linux_ata_device::linux_ata_device(smart_interface * i Line 245  linux_ata_device::linux_ata_device(smart_interface * i
 //   0 if the command succeeded and disk SMART status is "OK"  //   0 if the command succeeded and disk SMART status is "OK"
 //   1 if the command succeeded and disk SMART status is "FAILING"  //   1 if the command succeeded and disk SMART status is "FAILING"
   
   
 #define BUFFER_LENGTH (4+512)  #define BUFFER_LENGTH (4+512)
   
 int linux_ata_device::ata_command_interface(smart_command_set command, int select, char * data)  int linux_ata_device::ata_command_interface(smart_command_set command, int select, char * data)
Line 849  linux_scsi_device::linux_scsi_device(smart_interface * Line 851  linux_scsi_device::linux_scsi_device(smart_interface *
 {  {
 }  }
   
   
 bool linux_scsi_device::scsi_pass_through(scsi_cmnd_io * iop)  bool linux_scsi_device::scsi_pass_through(scsi_cmnd_io * iop)
 {  {
   int status = do_normal_scsi_cmnd_io(get_fd(), iop, scsi_debugmode);    int status = do_normal_scsi_cmnd_io(get_fd(), iop, scsi_debugmode);
Line 875  class linux_megaraid_device (public) Line 876  class linux_megaraid_device (public)
   
   virtual bool open();    virtual bool open();
   virtual bool close();    virtual bool close();
 
   virtual bool scsi_pass_through(scsi_cmnd_io *iop);    virtual bool scsi_pass_through(scsi_cmnd_io *iop);
   
 private:  private:
Line 885  class linux_megaraid_device (public) Line 886  class linux_megaraid_device (public)
   int m_fd;    int m_fd;
   
   bool (linux_megaraid_device::*pt_cmd)(int cdblen, void *cdb, int dataLen, void *data,    bool (linux_megaraid_device::*pt_cmd)(int cdblen, void *cdb, int dataLen, void *data,
    int senseLen, void *sense, int report);    int senseLen, void *sense, int report, int direction);
   bool megasas_cmd(int cdbLen, void *cdb, int dataLen, void *data,    bool megasas_cmd(int cdbLen, void *cdb, int dataLen, void *data,
    int senseLen, void *sense, int report);    int senseLen, void *sense, int report, int direction);
   bool megadev_cmd(int cdbLen, void *cdb, int dataLen, void *data,    bool megadev_cmd(int cdbLen, void *cdb, int dataLen, void *data,
    int senseLen, void *sense, int report);    int senseLen, void *sense, int report, int direction);
 };  };
   
 linux_megaraid_device::linux_megaraid_device(smart_interface *intf,  linux_megaraid_device::linux_megaraid_device(smart_interface *intf,
Line 900  linux_megaraid_device::linux_megaraid_device(smart_int Line 901  linux_megaraid_device::linux_megaraid_device(smart_int
    m_fd(-1), pt_cmd(0)     m_fd(-1), pt_cmd(0)
 {  {
   set_info().info_name = strprintf("%s [megaraid_disk_%02d]", dev_name, m_disknum);    set_info().info_name = strprintf("%s [megaraid_disk_%02d]", dev_name, m_disknum);
     set_info().dev_type = strprintf("megaraid,%d", tgt);
 }  }
   
 linux_megaraid_device::~linux_megaraid_device() throw()  linux_megaraid_device::~linux_megaraid_device() throw()
Line 939  smart_device * linux_megaraid_device::autodetect_open( Line 941  smart_device * linux_megaraid_device::autodetect_open(
   
   // Use INQUIRY to detect type    // Use INQUIRY to detect type
   {    {
    // SAT or USB ?    // SAT?
     ata_device * newdev = smi()->autodetect_sat_device(this, req_buff, len);      ata_device * newdev = smi()->autodetect_sat_device(this, req_buff, len);
    if (newdev) {    if (newdev) // NOTE: 'this' is now owned by '*newdev'
      // NOTE: 'this' is now owned by '*newdev' 
      newdev->close(); 
      newdev->set_err(ENOSYS, "SATA device detected,\n" 
        "MegaRAID SAT layer is reportedly buggy, use '-d sat+megaraid,N' to try anyhow"); 
       return newdev;        return newdev;
     }  
   }    }
   
   // Nothing special found    // Nothing special found
   return this;    return this;
 }  }
   
   
 bool linux_megaraid_device::open()  bool linux_megaraid_device::open()
 {  {
   char line[128];    char line[128];
  int   mjr, n1;  int   mjr;
  FILE *fp; 
   int report = scsi_debugmode;    int report = scsi_debugmode;
   
  if (!linux_smart_device::open())  if(sscanf(get_dev_name(),"/dev/bus/%d", &m_hba) == 0) {
    return false;    if (!linux_smart_device::open())
      return false;
  /* Get device HBA */    /* Get device HBA */
  struct sg_scsi_id sgid;    struct sg_scsi_id sgid;
  if (ioctl(get_fd(), SG_GET_SCSI_ID, &sgid) == 0) {    if (ioctl(get_fd(), SG_GET_SCSI_ID, &sgid) == 0) {
    m_hba = sgid.host_no;      m_hba = sgid.host_no;
  }    }
  else if (ioctl(get_fd(), SCSI_IOCTL_GET_BUS_NUMBER, &m_hba) != 0) {    else if (ioctl(get_fd(), SCSI_IOCTL_GET_BUS_NUMBER, &m_hba) != 0) {
    int err = errno;      int err = errno;
       linux_smart_device::close();
       return set_err(err, "can't get bus number");
     } // we dont need this device anymore
     linux_smart_device::close();      linux_smart_device::close();
     return set_err(err, "can't get bus number");  
   }    }
   
   /* Perform mknod of device ioctl node */    /* Perform mknod of device ioctl node */
  fp = fopen("/proc/devices", "r");  FILE * fp = fopen("/proc/devices", "r");
   while (fgets(line, sizeof(line), fp) != NULL) {    while (fgets(line, sizeof(line), fp) != NULL) {
        n1=0;    int n1 = 0;
        if (sscanf(line, "%d megaraid_sas_ioctl%n", &mjr, &n1) == 1 && n1 == 22) {    if (sscanf(line, "%d megaraid_sas_ioctl%n", &mjr, &n1) == 1 && n1 == 22) {
           n1=mknod("/dev/megaraid_sas_ioctl_node", S_IFCHR, makedev(mjr, 0));      n1=mknod("/dev/megaraid_sas_ioctl_node", S_IFCHR, makedev(mjr, 0));
           if(report > 0)      if(report > 0)
             pout("Creating /dev/megaraid_sas_ioctl_node = %d\n", n1 >= 0 ? 0 : errno);        pout("Creating /dev/megaraid_sas_ioctl_node = %d\n", n1 >= 0 ? 0 : errno);
           if (n1 >= 0 || errno == EEXIST)      if (n1 >= 0 || errno == EEXIST)
              break;        break;
        }    }
        else if (sscanf(line, "%d megadev%n", &mjr, &n1) == 1 && n1 == 11) {    else if (sscanf(line, "%d megadev%n", &mjr, &n1) == 1 && n1 == 11) {
           n1=mknod("/dev/megadev0", S_IFCHR, makedev(mjr, 0));      n1=mknod("/dev/megadev0", S_IFCHR, makedev(mjr, 0));
           if(report > 0)      if(report > 0)
             pout("Creating /dev/megadev0 = %d\n", n1 >= 0 ? 0 : errno);        pout("Creating /dev/megadev0 = %d\n", n1 >= 0 ? 0 : errno);
           if (n1 >= 0 || errno == EEXIST)      if (n1 >= 0 || errno == EEXIST)
              break;        break;
        }    }
   }    }
   fclose(fp);    fclose(fp);
   
Line 1009  bool linux_megaraid_device::open() Line 1005  bool linux_megaraid_device::open()
     linux_smart_device::close();      linux_smart_device::close();
     return set_err(err, "cannot open /dev/megaraid_sas_ioctl_node or /dev/megadev0");      return set_err(err, "cannot open /dev/megaraid_sas_ioctl_node or /dev/megadev0");
   }    }
  set_fd(m_fd);
   return true;    return true;
 }  }
   
Line 1018  bool linux_megaraid_device::close() Line 1014  bool linux_megaraid_device::close()
   if (m_fd >= 0)    if (m_fd >= 0)
     ::close(m_fd);      ::close(m_fd);
   m_fd = -1; m_hba = 0; pt_cmd = 0;    m_fd = -1; m_hba = 0; pt_cmd = 0;
  return linux_smart_device::close();  set_fd(m_fd);
   return true;
 }  }
   
 bool linux_megaraid_device::scsi_pass_through(scsi_cmnd_io *iop)  bool linux_megaraid_device::scsi_pass_through(scsi_cmnd_io *iop)
Line 1061  bool linux_megaraid_device::scsi_pass_through(scsi_cmn Line 1058  bool linux_megaraid_device::scsi_pass_through(scsi_cmn
       return set_err(ENOSYS, "ATA return descriptor not supported by controller firmware");        return set_err(ENOSYS, "ATA return descriptor not supported by controller firmware");
   }    }
   // SMART WRITE LOG SECTOR causing media errors    // SMART WRITE LOG SECTOR causing media errors
  if ((iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16 && iop->cmnd[14] == ATA_SMART_CMD   if ((iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16 // SAT16 WRITE LOG
        && iop->cmnd[3]==0 && iop->cmnd[4] == ATA_SMART_WRITE_LOG_SECTOR) ||       && iop->cmnd[14] == ATA_SMART_CMD && iop->cmnd[3]==0 && iop->cmnd[4] == ATA_SMART_WRITE_LOG_SECTOR) ||
      (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 && iop->cmnd[9] == ATA_SMART_CMD &&      (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 // SAT12 WRITE LOG
        iop->cmnd[3] == ATA_SMART_WRITE_LOG_SECTOR)       && iop->cmnd[9] == ATA_SMART_CMD && iop->cmnd[3] == ATA_SMART_WRITE_LOG_SECTOR)
    return set_err(ENOSYS, "SMART WRITE LOG SECTOR command is not supported by controller firmware");   {
    if(!failuretest_permissive)
        return set_err(ENOSYS, "SMART WRITE LOG SECTOR may cause problems, try with -T permissive to force"); 
   }
   if (pt_cmd == NULL)    if (pt_cmd == NULL)
     return false;      return false;
  return (this->*pt_cmd)(iop->cmnd_len, iop->cmnd,   return (this->*pt_cmd)(iop->cmnd_len, iop->cmnd,
     iop->dxfer_len, iop->dxferp,      iop->dxfer_len, iop->dxferp,
    iop->max_sense_len, iop->sensep, report);    iop->max_sense_len, iop->sensep, report, iop->dxfer_dir);
 }  }
   
 /* Issue passthrough scsi command to PERC5/6 controllers */  /* Issue passthrough scsi command to PERC5/6 controllers */
 bool linux_megaraid_device::megasas_cmd(int cdbLen, void *cdb,   bool linux_megaraid_device::megasas_cmd(int cdbLen, void *cdb, 
   int dataLen, void *data,    int dataLen, void *data,
  int /*senseLen*/, void * /*sense*/, int /*report*/)  int /*senseLen*/, void * /*sense*/, int /*report*/, int dxfer_dir)
 {  {
   struct megasas_pthru_frame    *pthru;    struct megasas_pthru_frame    *pthru;
   struct megasas_iocpacket      uio;    struct megasas_iocpacket      uio;
Line 1092  bool linux_megaraid_device::megasas_cmd(int cdbLen, vo Line 1091  bool linux_megaraid_device::megasas_cmd(int cdbLen, vo
   pthru->lun = 0;    pthru->lun = 0;
   pthru->cdb_len = cdbLen;    pthru->cdb_len = cdbLen;
   pthru->timeout = 0;    pthru->timeout = 0;
  pthru->flags = MFI_FRAME_DIR_READ;  switch (dxfer_dir) {
     case DXFER_NONE:
       pthru->flags = MFI_FRAME_DIR_NONE;
       break;
     case DXFER_FROM_DEVICE:
       pthru->flags = MFI_FRAME_DIR_READ;
       break;
     case DXFER_TO_DEVICE:
       pthru->flags = MFI_FRAME_DIR_WRITE;
       break;
     default:
       pout("megasas_cmd: bad dxfer_dir\n");
       return set_err(EINVAL, "megasas_cmd: bad dxfer_dir\n");
   }
 
   if (dataLen > 0) {    if (dataLen > 0) {
     pthru->sge_count = 1;      pthru->sge_count = 1;
     pthru->data_xfer_len = dataLen;      pthru->data_xfer_len = dataLen;
Line 1126  bool linux_megaraid_device::megasas_cmd(int cdbLen, vo Line 1139  bool linux_megaraid_device::megasas_cmd(int cdbLen, vo
 /* Issue passthrough scsi commands to PERC2/3/4 controllers */  /* Issue passthrough scsi commands to PERC2/3/4 controllers */
 bool linux_megaraid_device::megadev_cmd(int cdbLen, void *cdb,   bool linux_megaraid_device::megadev_cmd(int cdbLen, void *cdb, 
   int dataLen, void *data,    int dataLen, void *data,
  int /*senseLen*/, void * /*sense*/, int /*report*/)  int /*senseLen*/, void * /*sense*/, int /*report*/, int /* dir */)
 {  {
   struct uioctl_t uio;    struct uioctl_t uio;
   int rc;    int rc;
Line 1261  static int setup_3ware_nodes(const char *nodename, con Line 1274  static int setup_3ware_nodes(const char *nodename, con
   int                selinux_enforced = security_getenforce();    int                selinux_enforced = security_getenforce();
 #endif  #endif
   
   
   /* First try to open up /proc/devices */    /* First try to open up /proc/devices */
   if (!(file = fopen("/proc/devices", "r"))) {    if (!(file = fopen("/proc/devices", "r"))) {
     pout("Error opening /proc/devices to check/create 3ware device nodes\n");      pout("Error opening /proc/devices to check/create 3ware device nodes\n");
Line 1301  static int setup_3ware_nodes(const char *nodename, con Line 1313  static int setup_3ware_nodes(const char *nodename, con
 #endif  #endif
   /* Now check if nodes are correct */    /* Now check if nodes are correct */
   for (index=0; index<16; index++) {    for (index=0; index<16; index++) {
    sprintf(nodestring, "/dev/%s%d", nodename, index);    snprintf(nodestring, sizeof(nodestring), "/dev/%s%d", nodename, index);
 #ifdef WITH_SELINUX  #ifdef WITH_SELINUX
     /* Get context of the node and set it as the default */      /* Get context of the node and set it as the default */
     if (selinux_enabled) {      if (selinux_enabled) {
Line 1434  bool linux_escalade_device::open() Line 1446  bool linux_escalade_device::open()
 //   0 if the command succeeded and disk SMART status is "OK"  //   0 if the command succeeded and disk SMART status is "OK"
 //   1 if the command succeeded and disk SMART status is "FAILING"  //   1 if the command succeeded and disk SMART status is "FAILING"
   
   
 /* 512 is the max payload size: increase if needed */  /* 512 is the max payload size: increase if needed */
 #define BUFFER_LEN_678K      ( sizeof(TW_Ioctl)                  ) // 1044 unpacked, 1041 packed  #define BUFFER_LEN_678K      ( sizeof(TW_Ioctl)                  ) // 1044 unpacked, 1041 packed
 #define BUFFER_LEN_678K_CHAR ( sizeof(TW_New_Ioctl)+512-1        ) // 1539 unpacked, 1536 packed  #define BUFFER_LEN_678K_CHAR ( sizeof(TW_New_Ioctl)+512-1        ) // 1539 unpacked, 1536 packed
Line 1644  bool linux_escalade_device::ata_pass_through(const ata Line 1655  bool linux_escalade_device::ata_pass_through(const ata
   return true;    return true;
 }  }
   
   
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
 /// Areca RAID support  /// Areca RAID support
   
class linux_areca_device///////////////////////////////////////////////////////////////////
: public /*implements*/ ata_device,// SATA(ATA) device behind Areca RAID Controller
 class linux_areca_ata_device
 : public /*implements*/ areca_ata_device,
   public /*extends*/ linux_smart_device    public /*extends*/ linux_smart_device
 {  {
 public:  public:
  linux_areca_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1);  linux_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1);
  virtual smart_device * autodetect_open();
protected:  virtual bool arcmsr_lock();
  virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);   virtual bool arcmsr_unlock();
  virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop);
private: 
  int m_disknum; ///< Disk number. 
  int m_encnum;  ///< Enclosure number. 
 };  };
   
///////////////////////////////////////////////////////////////////
// PURPOSE// SAS(SCSI) device behind Areca RAID Controller
//   This is an interface routine meant to isolate the OS dependentclass linux_areca_scsi_device
//   parts of the code, and to provide a debugging interface.  Each: public /*implements*/ areca_scsi_device,
//   different port and OS needs to provide it's own interface.  This  public /*extends*/ linux_smart_device
//   is the linux interface to the Areca "arcmsr" driver.  It allows ATA 
//   commands to be passed through the SCSI driver. 
// DETAILED DESCRIPTION OF ARGUMENTS 
//   fd: is the file descriptor provided by open() 
//   disknum is the disk number (0 to 15) in the RAID array 
//   command: defines the different operations. 
//   select: additional input data if needed (which log, which type of 
//           self-test). 
//   data:   location to write output data, if needed (512 bytes). 
//   Note: not all commands use all arguments. 
// RETURN VALUES 
//  -1 if the command failed 
//   0 if the command succeeded, 
//   STATUS_CHECK routine:  
//  -1 if the command failed 
//   0 if the command succeeded and disk SMART status is "OK" 
//   1 if the command succeeded and disk SMART status is "FAILING" 
 
 
/*DeviceType*/ 
#define ARECA_SATA_RAID                         0x90000000 
/*FunctionCode*/ 
#define FUNCTION_READ_RQBUFFER                  0x0801 
#define FUNCTION_WRITE_WQBUFFER                 0x0802 
#define FUNCTION_CLEAR_RQBUFFER                 0x0803 
#define FUNCTION_CLEAR_WQBUFFER                 0x0804 
 
/* ARECA IO CONTROL CODE*/ 
#define ARCMSR_IOCTL_READ_RQBUFFER              (ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER) 
#define ARCMSR_IOCTL_WRITE_WQBUFFER             (ARECA_SATA_RAID | FUNCTION_WRITE_WQBUFFER) 
#define ARCMSR_IOCTL_CLEAR_RQBUFFER             (ARECA_SATA_RAID | FUNCTION_CLEAR_RQBUFFER) 
#define ARCMSR_IOCTL_CLEAR_WQBUFFER             (ARECA_SATA_RAID | FUNCTION_CLEAR_WQBUFFER) 
#define ARECA_SIG_STR                                                   "ARCMSR" 
 
// The SRB_IO_CONTROL & SRB_BUFFER structures are used to communicate(to/from) to areca driver 
typedef struct _SRB_IO_CONTROL 
 {  {
        unsigned int HeaderLength;public:
        unsigned char Signature[8];  linux_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1);
        unsigned int Timeout;  virtual smart_device * autodetect_open();
        unsigned int ControlCode;  virtual bool arcmsr_lock();
        unsigned int ReturnCode;  virtual bool arcmsr_unlock();
        unsigned int Length;  virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop);
} sSRB_IO_CONTROL;};
   
 typedef struct _SRB_BUFFER  
 {  
         sSRB_IO_CONTROL srbioctl;  
         unsigned char   ioctldatabuffer[1032]; // the buffer to put the command data to/from firmware  
 } sSRB_BUFFER;  
   
 // Looks in /proc/scsi to suggest correct areca devices  // Looks in /proc/scsi to suggest correct areca devices
// If hint not NULL, return device path guessstatic int find_areca_in_proc()
static int find_areca_in_proc(char *hint) 
 {  {
     const char* proc_format_string="host\tchan\tid\tlun\ttype\topens\tqdepth\tbusy\tonline\n";      const char* proc_format_string="host\tchan\tid\tlun\ttype\topens\tqdepth\tbusy\tonline\n";
   
Line 1760  static int find_areca_in_proc(char *hint) Line 1726  static int find_areca_in_proc(char *hint)
         dev++;          dev++;
         if (id == 16 && type == 3) {          if (id == 16 && type == 3) {
            // devices with id=16 and type=3 might be Areca controllers             // devices with id=16 and type=3 might be Areca controllers
            if (!found && hint) {  
                sprintf(hint, "/dev/sg%d", dev);  
            }  
            pout("Device /dev/sg%d appears to be an Areca controller.\n", dev);             pout("Device /dev/sg%d appears to be an Areca controller.\n", dev);
            found++;             found++;
         }          }
Line 1771  static int find_areca_in_proc(char *hint) Line 1734  static int find_areca_in_proc(char *hint)
     return 0;      return 0;
 }  }
   
   // Areca RAID Controller(SATA Disk)
   linux_areca_ata_device::linux_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
   : smart_device(intf, dev_name, "areca", "areca"),
     linux_smart_device(O_RDWR | O_EXCL | O_NONBLOCK)
   {
     set_disknum(disknum);
     set_encnum(encnum);
     set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
   }
   
#if 0 // For debugging areca codesmart_device * linux_areca_ata_device::autodetect_open()
 
static void dumpdata(unsigned char *block, int len) 
 {  {
        int ln = (len / 16) + 1;     // total line#  int is_ata = 1;
        unsigned char c; 
        int pos = 0; 
   
        printf(" Address = %p, Length = (0x%x)%d\n", block, len, len);  // autodetect device type
        printf("      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F      ASCII      \n");  is_ata = arcmsr_get_dev_type();
        printf("=====================================================================\n");  if(is_ata < 0)
   {
     set_err(EIO);
     return this;
   }
   
        for ( int l = 0; l < ln && len; l++ )  if(is_ata == 1)
        {  {
                // printf the line# and the HEX data    // SATA device
                // if a line data length < 16 then append the space to the tail of line to reach 16 chars    return this;
                printf("%02X | ", l);  }
                for ( pos = 0; pos < 16 && len; pos++, len-- ) 
                { 
                        c = block[l*16+pos];     
                        printf("%02X ", c); 
                } 
   
                if ( pos < 16 )  // SAS device
                {  smart_device_auto_ptr newdev(new linux_areca_scsi_device(smi(), get_dev_name(), get_disknum(), get_encnum()));
                        for ( int loop = pos; loop < 16; loop++ )  close();
                        {  delete this;
                                printf("   ");  newdev->open();       // TODO: Can possibly pass open fd
                        } 
                } 
   
                // print ASCII char  return newdev.release();
                for ( int loop = 0; loop < pos; loop++ ) 
                { 
                        c = block[l*16+loop]; 
                        if ( c >= 0x20 && c <= 0x7F ) 
                        { 
                                printf("%c", c); 
                        } 
                        else 
                        { 
                                printf("."); 
                        } 
                } 
                printf("\n"); 
        }    
        printf("=====================================================================\n"); 
 }  }
   
#endifint linux_areca_ata_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop)
 
static int arcmsr_command_handler(int fd, unsigned long arcmsr_cmd, unsigned char *data, int data_len, void *ext_data /* reserved for further use */) 
 {  {
        ARGUSED(ext_data);  int ioctlreturn = 0;
   
        int ioctlreturn = 0;  if(!is_open()) {
        sSRB_BUFFER sBuf;      if(!open()){
        struct scsi_cmnd_io io_hdr;            find_areca_in_proc();
        int dir = DXFER_TO_DEVICE;      }
   }
   
        UINT8 cdb[10];  ioctlreturn = do_normal_scsi_cmnd_io(get_fd(), iop, scsi_debugmode);
        UINT8 sense[32];  if ( ioctlreturn || iop->scsi_status )
   {
     // errors found
     return -1;
   }
   
        unsigned char *areca_return_packet;  return ioctlreturn;
        int total = 0;}
        int expected = -1; 
        unsigned char return_buff[2048]; 
        unsigned char *ptr = &return_buff[0]; 
        memset(return_buff, 0, sizeof(return_buff)); 
   
        memset((unsigned char *)&sBuf, 0, sizeof(sBuf));bool linux_areca_ata_device::arcmsr_lock()
        memset(&io_hdr, 0, sizeof(io_hdr));{
        memset(cdb, 0, sizeof(cdb));  return true;
        memset(sense, 0, sizeof(sense));}
   
bool linux_areca_ata_device::arcmsr_unlock()
        sBuf.srbioctl.HeaderLength = sizeof(sSRB_IO_CONTROL);   {
        memcpy(sBuf.srbioctl.Signature, ARECA_SIG_STR, strlen(ARECA_SIG_STR));  return true;
        sBuf.srbioctl.Timeout = 10000;       
        sBuf.srbioctl.ControlCode = ARCMSR_IOCTL_READ_RQBUFFER; 
 
        switch ( arcmsr_cmd ) 
        { 
        // command for writing data to driver 
        case ARCMSR_IOCTL_WRITE_WQBUFFER:    
                if ( data && data_len ) 
                { 
                        sBuf.srbioctl.Length = data_len;     
                        memcpy((unsigned char *)sBuf.ioctldatabuffer, (unsigned char *)data, data_len); 
                } 
                // commands for clearing related buffer of driver 
        case ARCMSR_IOCTL_CLEAR_RQBUFFER: 
        case ARCMSR_IOCTL_CLEAR_WQBUFFER: 
                cdb[0] = 0x3B; //SCSI_WRITE_BUF command; 
                break; 
                // command for reading data from driver 
        case ARCMSR_IOCTL_READ_RQBUFFER:     
                cdb[0] = 0x3C; //SCSI_READ_BUF command; 
                dir = DXFER_FROM_DEVICE; 
                break; 
        default: 
                // unknown arcmsr commands 
                return -1; 
        } 
 
        cdb[1] = 0x01; 
        cdb[2] = 0xf0;     
        // 
        // cdb[5][6][7][8] areca defined command code( to/from driver ) 
        //     
        cdb[5] = (char)( arcmsr_cmd >> 24); 
        cdb[6] = (char)( arcmsr_cmd >> 16); 
        cdb[7] = (char)( arcmsr_cmd >> 8); 
        cdb[8] = (char)( arcmsr_cmd & 0x0F ); 
 
        io_hdr.dxfer_dir = dir; 
        io_hdr.dxfer_len = sizeof(sBuf); 
        io_hdr.dxferp = (unsigned char *)&sBuf;   
        io_hdr.cmnd = cdb; 
        io_hdr.cmnd_len = sizeof(cdb); 
        io_hdr.sensep = sense;   
        io_hdr.max_sense_len = sizeof(sense); 
        io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; 
 
        while ( 1 ) 
        { 
                ioctlreturn = do_normal_scsi_cmnd_io(fd, &io_hdr, 0); 
                if ( ioctlreturn || io_hdr.scsi_status ) 
                { 
                        // errors found 
                        break; 
                } 
 
                if ( arcmsr_cmd != ARCMSR_IOCTL_READ_RQBUFFER ) 
                { 
                        // if succeeded, just returns the length of outgoing data 
                        return data_len; 
                } 
 
                if ( sBuf.srbioctl.Length ) 
                { 
                        //dumpdata(&sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length); 
                        memcpy(ptr, &sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length); 
                        ptr += sBuf.srbioctl.Length; 
                        total += sBuf.srbioctl.Length; 
                        // the returned bytes enough to compute payload length ? 
                        if ( expected < 0 && total >= 5 ) 
                        { 
                                areca_return_packet = (unsigned char *)&return_buff[0]; 
                                if ( areca_return_packet[0] == 0x5E &&  
                                         areca_return_packet[1] == 0x01 &&  
                                         areca_return_packet[2] == 0x61 ) 
                                { 
                                        // valid header, let's compute the returned payload length, 
                                        // we expected the total length is  
                                        // payload + 3 bytes header + 2 bytes length + 1 byte checksum 
                                        expected = areca_return_packet[4] * 256 + areca_return_packet[3] + 6; 
                                } 
                        } 
 
                        if ( total >= 7 && total >= expected ) 
                        { 
                                //printf("total bytes received = %d, expected length = %d\n", total, expected); 
 
                                // ------ Okay! we received enough -------- 
                                break; 
                        } 
                } 
        } 
 
        // Deal with the different error cases 
        if ( ioctlreturn ) 
        { 
                pout("do_scsi_cmnd_io with write buffer failed code = %x\n", ioctlreturn); 
                return -2; 
        } 
 
 
        if ( io_hdr.scsi_status ) 
        { 
                pout("io_hdr.scsi_status with write buffer failed code = %x\n", io_hdr.scsi_status); 
                return -3; 
        } 
 
 
        if ( data ) 
        { 
                memcpy(data, return_buff, total); 
        } 
 
        return total; 
 }  }
   
// Areca RAID Controller(SAS Device)
linux_areca_device::linux_areca_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)linux_areca_scsi_device::linux_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
 : smart_device(intf, dev_name, "areca", "areca"),  : smart_device(intf, dev_name, "areca", "areca"),
  linux_smart_device(O_RDWR | O_EXCL | O_NONBLOCK),  linux_smart_device(O_RDWR | O_EXCL | O_NONBLOCK)
  m_disknum(disknum), 
  m_encnum(encnum) 
 {  {
     set_disknum(disknum);
     set_encnum(encnum);
   set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);    set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
 }  }
   
// Areca RAID Controllersmart_device * linux_areca_scsi_device::autodetect_open()
// int linux_areca_device::ata_command_interface(smart_command_set command, int select, char * data) 
bool linux_areca_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)  
 {  {
if (!ata_cmd_is_ok(in,   return this;
    true, // data_out_support }
    false, // TODO: multi_sector_support  
    true) // ata_48bit_support  
    ) 
    return false;  
   
        // ATA input registersint linux_areca_scsi_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop)
        typedef struct _ATA_INPUT_REGISTERS{
        {  int ioctlreturn = 0;
                unsigned char features; 
                unsigned char sector_count; 
                unsigned char sector_number; 
                unsigned char cylinder_low;  
                unsigned char cylinder_high;     
                unsigned char device_head;   
                unsigned char command;       
                unsigned char reserved[8]; 
                unsigned char data[512]; // [in/out] buffer for outgoing/incoming data 
        } sATA_INPUT_REGISTERS; 
   
        // ATA output registers  if(!is_open()) {
        // Note: The output registers is re-sorted for areca internal use only      if(!open()){
        typedef struct _ATA_OUTPUT_REGISTERS          find_areca_in_proc();
        {      }
                unsigned char error;  }
                unsigned char status; 
                unsigned char sector_count; 
                unsigned char sector_number; 
                unsigned char cylinder_low;  
                unsigned char cylinder_high; 
        }sATA_OUTPUT_REGISTERS; 
   
        // Areca packet format for outgoing:  ioctlreturn = do_normal_scsi_cmnd_io(get_fd(), iop, scsi_debugmode);
        // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61  if ( ioctlreturn || iop->scsi_status )
        // B[3~4] : 2 bytes command length + variant data length, little endian  {
        // B[5]   : 1 bytes areca defined command code, ATA passthrough command code is 0x1c    // errors found
        // B[6~last-1] : variant bytes payload data    return -1;
        // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])  }
        //  
        //  
        //   header 3 bytes  length 2 bytes   cmd 1 byte    payload data x bytes  cs 1 byte  
        // +--------------------------------------------------------------------------------+ 
        // + 0x5E 0x01 0x61 |   0x00 0x00   |     0x1c   | .................... |   0x00    | 
        // +--------------------------------------------------------------------------------+ 
        //  
   
        //Areca packet format for incoming:  return ioctlreturn;
        // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61}
        // B[3~4] : 2 bytes payload length, little endian 
        // B[5~last-1] : variant bytes returned payload data 
        // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1]) 
        //  
        //  
        //   header 3 bytes  length 2 bytes   payload data x bytes  cs 1 byte  
        // +-------------------------------------------------------------------+ 
        // + 0x5E 0x01 0x61 |   0x00 0x00   | .................... |   0x00    | 
        // +-------------------------------------------------------------------+ 
        unsigned char    areca_packet[640]; 
        int areca_packet_len = sizeof(areca_packet); 
        unsigned char cs = 0;    
   
        sATA_INPUT_REGISTERS *ata_cmd;bool linux_areca_scsi_device::arcmsr_lock()
 {
   return true;
 }
   
        // For debuggingbool linux_areca_scsi_device::arcmsr_unlock()
#if 0{
        memset(sInq, 0, sizeof(sInq));  return true;
        scsiStdInquiry(fd, (unsigned char *)sInq, (int)sizeof(sInq)); 
        dumpdata((unsigned char *)sInq, sizeof(sInq)); 
#endif 
        memset(areca_packet, 0, areca_packet_len); 
 
        // ----- BEGIN TO SETUP HEADERS ------- 
        areca_packet[0] = 0x5E; 
        areca_packet[1] = 0x01; 
        areca_packet[2] = 0x61; 
        areca_packet[3] = (unsigned char)((areca_packet_len - 6) & 0xff); 
        areca_packet[4] = (unsigned char)(((areca_packet_len - 6) >> 8) & 0xff); 
        areca_packet[5] = 0x1c; // areca defined code for ATA passthrough command 
 
        // ----- BEGIN TO SETUP PAYLOAD DATA ----- 
        memcpy(&areca_packet[7], "SmrT", 4);    // areca defined password 
        ata_cmd = (sATA_INPUT_REGISTERS *)&areca_packet[12]; 
 
        // Set registers 
        { 
            const ata_in_regs_48bit & r = in.in_regs; 
            ata_cmd->features     = r.features_16; 
            ata_cmd->sector_count  = r.sector_count_16; 
            ata_cmd->sector_number = r.lba_low_16; 
            ata_cmd->cylinder_low  = r.lba_mid_16; 
            ata_cmd->cylinder_high = r.lba_high_16; 
            ata_cmd->device_head   = r.device; 
            ata_cmd->command      = r.command; 
        } 
        bool readdata = false;  
        if (in.direction == ata_cmd_in::data_in) {  
            readdata = true; 
            // the command will read data 
            areca_packet[6] = 0x13; 
        } 
        else if ( in.direction == ata_cmd_in::no_data ) 
        { 
                // the commands will return no data 
                areca_packet[6] = 0x15; 
        } 
        else if (in.direction == ata_cmd_in::data_out)  
        { 
                // the commands will write data 
                memcpy(ata_cmd->data, in.buffer, in.size); 
                areca_packet[6] = 0x14; 
        } 
        else { 
            // COMMAND NOT SUPPORTED VIA ARECA IOCTL INTERFACE 
            return set_err(ENOTSUP, "DATA OUT not supported for this Areca controller type"); 
        } 
 
        areca_packet[11] = m_disknum - 1;  // disk# 
        areca_packet[19] = m_encnum - 1;   // enc# 
 
        // ----- BEGIN TO SETUP CHECKSUM ----- 
        for ( int loop = 3; loop < areca_packet_len - 1; loop++ ) 
        { 
                cs += areca_packet[loop];  
        } 
        areca_packet[areca_packet_len-1] = cs; 
 
        // ----- BEGIN TO SEND TO ARECA DRIVER ------ 
        int expected = 0;        
        unsigned char return_buff[2048]; 
        memset(return_buff, 0, sizeof(return_buff)); 
 
        expected = arcmsr_command_handler(get_fd(), ARCMSR_IOCTL_CLEAR_RQBUFFER, NULL, 0, NULL); 
        if (expected==-3) { 
            find_areca_in_proc(NULL); 
            return set_err(EIO); 
        } 
 
        expected = arcmsr_command_handler(get_fd(), ARCMSR_IOCTL_CLEAR_WQBUFFER, NULL, 0, NULL); 
        expected = arcmsr_command_handler(get_fd(), ARCMSR_IOCTL_WRITE_WQBUFFER, areca_packet, areca_packet_len, NULL); 
        if ( expected > 0 ) 
        { 
                expected = arcmsr_command_handler(get_fd(), ARCMSR_IOCTL_READ_RQBUFFER, return_buff, sizeof(return_buff), NULL); 
        } 
        if ( expected < 0 ) 
        { 
                return -1; 
        } 
 
        // ----- VERIFY THE CHECKSUM ----- 
        cs = 0; 
        for ( int loop = 3; loop < expected - 1; loop++ ) 
        { 
                cs += return_buff[loop];  
        } 
 
        if ( return_buff[expected - 1] != cs ) 
        { 
                return set_err(EIO); 
        } 
 
        sATA_OUTPUT_REGISTERS *ata_out = (sATA_OUTPUT_REGISTERS *)&return_buff[5] ; 
        if ( ata_out->status ) 
        { 
                if ( in.in_regs.command == ATA_IDENTIFY_DEVICE 
                 && !nonempty((unsigned char *)in.buffer, in.size))  
                 { 
                    return set_err(ENODEV, "No drive on port %d", m_disknum); 
                 }  
        } 
 
        // returns with data 
        if (readdata) 
        { 
                memcpy(in.buffer, &return_buff[7], in.size);  
        } 
 
        // Return register values 
        { 
            ata_out_regs_48bit & r = out.out_regs; 
            r.error           = ata_out->error; 
            r.sector_count_16 = ata_out->sector_count; 
            r.lba_low_16      = ata_out->sector_number; 
            r.lba_mid_16      = ata_out->cylinder_low; 
            r.lba_high_16     = ata_out->cylinder_high; 
            r.status          = ata_out->status; 
        } 
        return true; 
 }  }
   
   
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
 /// Marvell support  /// Marvell support
   
Line 2317  int linux_marvell_device::ata_command_interface(smart_ Line 1993  int linux_marvell_device::ata_command_interface(smart_
   return 0;    return 0;
 }  }
   
   
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
 /// Highpoint RAID support  /// Highpoint RAID support
   
Line 2550  int linux_highpoint_device::ata_command_interface(smar Line 2225  int linux_highpoint_device::ata_command_interface(smar
   return 0;    return 0;
 }  }
   
   
 #if 0 // TODO: Migrate from 'smart_command_set' to 'ata_in_regs' OR remove the function  #if 0 // TODO: Migrate from 'smart_command_set' to 'ata_in_regs' OR remove the function
 // Utility function for printing warnings  // Utility function for printing warnings
 void printwarning(smart_command_set command){  void printwarning(smart_command_set command){
Line 2582  void printwarning(smart_command_set command){ Line 2256  void printwarning(smart_command_set command){
 }  }
 #endif  #endif
   
   
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
 /// SCSI open with autodetection support  /// SCSI open with autodetection support
   
Line 2640  smart_device * linux_scsi_device::autodetect_open() Line 2313  smart_device * linux_scsi_device::autodetect_open()
     }      }
   
     // DELL?      // DELL?
    if (!memcmp(req_buff + 8, "DELL    PERC", 12) || !memcmp(req_buff + 8, "MegaRAID", 8)) {    if (!memcmp(req_buff + 8, "DELL    PERC", 12) || !memcmp(req_buff + 8, "MegaRAID", 8)
         || !memcmp(req_buff + 16, "PERC H700", 9) || !memcmp(req_buff + 8, "LSI\0",4)
     ) {
       close();        close();
       set_err(EINVAL, "DELL or MegaRaid controller, please try adding '-d megaraid,N'");        set_err(EINVAL, "DELL or MegaRaid controller, please try adding '-d megaraid,N'");
       return this;        return this;
Line 2676  smart_device * linux_scsi_device::autodetect_open() Line 2351  smart_device * linux_scsi_device::autodetect_open()
   return this;    return this;
 }  }
   
   
 //////////////////////////////////////////////////////////////////////  //////////////////////////////////////////////////////////////////////
 // USB bridge ID detection  // USB bridge ID detection
   
Line 2730  static bool get_usb_id(const char * name, unsigned sho Line 2404  static bool get_usb_id(const char * name, unsigned sho
   return true;    return true;
 }  }
   
   
 //////////////////////////////////////////////////////////////////////  //////////////////////////////////////////////////////////////////////
 /// Linux interface  /// Linux interface
   
Line 2759  class linux_smart_interface (protected) Line 2432  class linux_smart_interface (protected)
 private:  private:
   bool get_dev_list(smart_device_list & devlist, const char * pattern,    bool get_dev_list(smart_device_list & devlist, const char * pattern,
     bool scan_ata, bool scan_scsi, const char * req_type, bool autodetect);      bool scan_ata, bool scan_scsi, const char * req_type, bool autodetect);
  bool get_dev_megasas(smart_device_list & devlist);
   smart_device * missing_option(const char * opt);    smart_device * missing_option(const char * opt);
     int megasas_dcmd_cmd(int bus_no, uint32_t opcode, void *buf,
       size_t bufsize, uint8_t *mbox, size_t mboxlen, uint8_t *statusp);
     int megasas_pd_add_list(int bus_no, smart_device_list & devlist);
 };  };
   
 std::string linux_smart_interface::get_os_version_str()  std::string linux_smart_interface::get_os_version_str()
Line 2779  std::string linux_smart_interface::get_app_examples(co Line 2455  std::string linux_smart_interface::get_app_examples(co
   return "";    return "";
 }  }
   
   
 // we are going to take advantage of the fact that Linux's devfs will only  // 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  // 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  // ls /dev/hd[a-t], we have all the ATA devices on the system
Line 2876  bool linux_smart_interface::get_dev_list(smart_device_ Line 2551  bool linux_smart_interface::get_dev_list(smart_device_
   
   // free memory    // free memory
   globfree(&globbuf);    globfree(&globbuf);
     return true;
   }
   
   // getting devices from LSI SAS MegaRaid, if available
   bool linux_smart_interface::get_dev_megasas(smart_device_list & devlist)
   {
     /* Scanning of disks on MegaRaid device */
     /* Perform mknod of device ioctl node */
     int   mjr, n1;
     char line[128];
     bool scan_megasas = false;
     FILE * fp = fopen("/proc/devices", "r");
     while (fgets(line, sizeof(line), fp) != NULL) {
       n1=0;
       if (sscanf(line, "%d megaraid_sas_ioctl%n", &mjr, &n1) == 1 && n1 == 22) {
         scan_megasas = true;
         n1=mknod("/dev/megaraid_sas_ioctl_node", S_IFCHR, makedev(mjr, 0));
         if(scsi_debugmode > 0)
           pout("Creating /dev/megaraid_sas_ioctl_node = %d\n", n1 >= 0 ? 0 : errno);
         if (n1 >= 0 || errno == EEXIST)
           break;
       }
     }
     fclose(fp);
   
     if(!scan_megasas)
       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 */
     DIR * dp = opendir ("/sys/class/scsi_host/");
     if (dp != NULL)
     {
       while ((ep = readdir (dp)) != NULL) {
         if (!sscanf(ep->d_name, "host%d", &host_no)) 
           continue;
         /* proc_name should be megaraid_sas */
         snprintf(sysfsdir, sizeof(sysfsdir) - 1,
           "/sys/class/scsi_host/host%d/proc_name", host_no);
         if((fp = fopen(sysfsdir, "r")) == NULL)
           continue;
         if(fgets(line, sizeof(line), fp) != NULL && !strncmp(line,"megaraid_sas",12)) {
           megasas_pd_add_list(host_no, devlist);
         }
         fclose(fp);
       }
       (void) closedir (dp);
     } else { /* sysfs not mounted ? */
       for(unsigned i = 0; i <=16; i++) // trying to add devices on first 16 buses
         megasas_pd_add_list(i, devlist);
     }
   return true;    return true;
 }  }
   
Line 2904  bool linux_smart_interface::scan_smart_devices(smart_d Line 2633  bool linux_smart_interface::scan_smart_devices(smart_d
     get_dev_list(devlist, "/dev/sd[a-z]", false, true, type, autodetect);      get_dev_list(devlist, "/dev/sd[a-z]", false, true, type, autodetect);
     // Support up to 104 devices      // Support up to 104 devices
     get_dev_list(devlist, "/dev/sd[a-c][a-z]", false, true, type, autodetect);      get_dev_list(devlist, "/dev/sd[a-c][a-z]", false, true, type, autodetect);
       // get device list from the megaraid device
       get_dev_megasas(devlist);
   }    }
   
   // if we found traditional links, we are done    // if we found traditional links, we are done
Line 2931  smart_device * linux_smart_interface::missing_option(c Line 2662  smart_device * linux_smart_interface::missing_option(c
   return 0;    return 0;
 }  }
   
   int
   linux_smart_interface::megasas_dcmd_cmd(int bus_no, uint32_t opcode, void *buf,
     size_t bufsize, uint8_t *mbox, size_t mboxlen, uint8_t *statusp)
   {
     struct megasas_iocpacket ioc;
   
     if ((mbox != NULL && (mboxlen == 0 || mboxlen > MFI_MBOX_SIZE)) ||
       (mbox == NULL && mboxlen != 0)) 
     {
       errno = EINVAL;
       return (-1);
     }
   
     bzero(&ioc, sizeof(ioc));
     struct megasas_dcmd_frame * dcmd = &ioc.frame.dcmd;
     ioc.host_no = bus_no;
     if (mbox)
       bcopy(mbox, dcmd->mbox.w, mboxlen);
     dcmd->cmd = MFI_CMD_DCMD;
     dcmd->timeout = 0;
     dcmd->flags = 0;
     dcmd->data_xfer_len = bufsize;
     dcmd->opcode = opcode;
   
     if (bufsize > 0) {
       dcmd->sge_count = 1;
       dcmd->data_xfer_len = bufsize;
       dcmd->sgl.sge32[0].phys_addr = (intptr_t)buf;
       dcmd->sgl.sge32[0].length = (uint32_t)bufsize;
       ioc.sge_count = 1;
       ioc.sgl_off = offsetof(struct megasas_dcmd_frame, sgl);
       ioc.sgl[0].iov_base = buf;
       ioc.sgl[0].iov_len = bufsize;
     }
   
     int fd;
     if ((fd = ::open("/dev/megaraid_sas_ioctl_node", O_RDWR)) <= 0) {
       return (errno);
     }
   
     int r = ioctl(fd, MEGASAS_IOC_FIRMWARE, &ioc);
     if (r < 0) {
       return (r);
     }
   
     if (statusp != NULL)
       *statusp = dcmd->cmd_status;
     else if (dcmd->cmd_status != MFI_STAT_OK) {
       fprintf(stderr, "command %x returned error status %x\n",
         opcode, dcmd->cmd_status);
       errno = EIO;
       return (-1);
     }
     return (0);
   }
   
   int
   linux_smart_interface::megasas_pd_add_list(int bus_no, smart_device_list & devlist)
   {
     /*
     * Keep fetching the list in a loop until we have a large enough
     * buffer to hold the entire list.
     */
     megasas_pd_list * list = 0;
     for (unsigned list_size = 1024; ; ) {
       list = (megasas_pd_list *)realloc(list, list_size);
       if (!list)
         throw std::bad_alloc();
       bzero(list, list_size);
       if (megasas_dcmd_cmd(bus_no, MFI_DCMD_PD_GET_LIST, list, list_size, NULL, 0,
         NULL) < 0) 
       {
         free(list);
         return (-1);
       }
       if (list->size <= list_size)
         break;
       list_size = list->size;
     }
   
     // adding all SCSI devices
     for (unsigned i = 0; i < list->count; i++) {
       if(list->addr[i].scsi_dev_type)
         continue; /* non disk device found */
       char line[128];
       snprintf(line, sizeof(line) - 1, "/dev/bus/%d", bus_no);
       smart_device * dev = new linux_megaraid_device(this, line, 0, list->addr[i].device_id);
       devlist.push_back(dev);
     }
     free(list);
     return (0);
   }
   
 // Return kernel release as integer ("2.6.31" -> 206031)  // Return kernel release as integer ("2.6.31" -> 206031)
 static unsigned get_kernel_release()  static unsigned get_kernel_release()
 {  {
Line 3068  smart_device * linux_smart_interface::get_custom_smart Line 2892  smart_device * linux_smart_interface::get_custom_smart
       set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum);        set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum);
       return 0;        return 0;
     }      }
    return new linux_areca_device(this, name, disknum, encnum);    return new linux_areca_ata_device(this, name, disknum, encnum);
   }    }
   
   // Highpoint ?    // Highpoint ?
Line 3128  std::string linux_smart_interface::get_valid_custom_de Line 2952  std::string linux_smart_interface::get_valid_custom_de
 }  }
   
 } // namespace  } // namespace
   
   
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
 /// Initialize platform interface and register with smi()  /// Initialize platform interface and register with smi()

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>