Index: smartctl.8.in
===================================================================
--- smartctl.8.in	(revision 3892)
+++ smartctl.8.in	(working copy)
@@ -380,6 +380,26 @@
 .fi
 For PERC5/6 controllers: \fBmegaraid_sas_ioctlN\fP
 
+.I aacraid,L,ID
+\- [Linux only] the device consists of one or more SCSI/SAS disks connected
+to a AacRaid controller.  The non-negative integer L is the Lun number and ID is the id number both of which 
+denotes which disk on the controller is monitored.
+Use syntax such as:
+.nf
+\fBsmartctl \-a \-d aacraid,0,66 /dev/sda\fP
+.fi
+.nf
+\fBsmartctl \-a \-d aacraid,0,66 /dev/sdb\fP
+.fi
+
+The L and ID numbers of a disk can be found in 
+/proc/scsi/scsi
+
+The following entry in /proc/devices must exist:
+.fi
+ \fBaac\fP
+
+
 .\" %ENDIF OS Linux
 .\" %IF OS FreeBSD Linux
 .I 3ware,N
Index: smartd.conf.5.in
===================================================================
--- smartd.conf.5.in	(revision 3892)
+++ smartd.conf.5.in	(working copy)
@@ -146,6 +146,17 @@
 .B #
 .\" %ENDIF OS Linux
 .nf
+.\" %IF OS Linux
+.B # Three disks connected to a AacRaid controller
+.B # Start short self-tests daily between 1-2, 2-3, and
+.B # 3-4 am.
+.B \ \ /dev/sda -d aacraid,0,66 -a -s S/../.././01
+.B \ \ /dev/sda -d aacraid,0,67 -a -s S/../.././02
+.B \ \ /dev/sda -d aacraid,0,68 -a -s S/../.././03
+.B
+.B #
+.\" %ENDIF OS Linux
+.nf
 .B # Four ATA disks on a 3ware 6/7/8000 controller.
 .B # Start short self-tests daily between midnight and 1am,
 .B # 1-2, 2-3, and 3-4 am.  Starting with the Linux 2.6
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 3892)
+++ ChangeLog	(working copy)
@@ -1,5 +1,12 @@
 $Id$
 
+2014-04-18  Raghava Aditya  <Raghava.Aditya@pmcs.com>
+
+	os_linux.cpp
+	- Added support for aacraid drivers
+	- Created a new interface for aacraid
+	         smartctl -d aacraid,L,ID /dev/sdx
+	          
 2014-04-18  Douglas Gilbert  <dgilbert@interlog.com>
 
 	scsicmds.cpp:
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 3892)
+++ Makefile.am	(working copy)
@@ -102,7 +102,8 @@
         dev_areca.cpp \
         dev_areca.h \
         dev_legacy.cpp \
-        megaraid.h
+        megaraid.h \
+		aacraid.h
 
 if OS_WIN32_MINGW
 
@@ -161,7 +162,8 @@
         dev_areca.cpp \
         dev_areca.h \
         dev_legacy.cpp \
-        megaraid.h
+        megaraid.h \
+		aacraid.h
 
 if OS_WIN32_MINGW
 
Index: os_linux.cpp
===================================================================
--- os_linux.cpp	(revision 3892)
+++ os_linux.cpp	(working copy)
@@ -3,6 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
+ * Copyright (C) 2014 Raghava Aditya <Raghava.Aditya@pmcs.com>
  * Copyright (C) 2003-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
  * Copyright (C) 2003-11 Doug Gilbert <dgilbert@interlog.com>
  * Copyright (C) 2008-12 Hank Wu <hank@areca.com.tw>
@@ -80,6 +81,7 @@
 #include "utility.h"
 #include "cciss.h"
 #include "megaraid.h"
+#include "aacraid.h"
 
 #include "dev_interface.h"
 #include "dev_ata_cmd_set.h"
@@ -860,6 +862,217 @@
 }
 
 /////////////////////////////////////////////////////////////////////////////
+/// 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:
+  int afd;
+
+  //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),
+     afd(-1), 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];
+  sprintf(dev_name,"/dev/aac%d",aHost);
+
+  //Initial open of dev name to check if it exsists
+  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;
+    int nc  = -1;
+
+    while(fgets(line,sizeof(line),fp) !=NULL) {
+      if(sscanf(line,"%d aac%n",&mjr,&nc) == 1
+                && nc > 0 && '\n' == line[nc])
+        break;
+    }
+
+    //work with /proc/devices is done
+    fclose(fp);
+
+    //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;
+    pReply  = (user_aac_reply*)(aBuff+sizeof(user_aac_srb64));
+
+ #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;
+    pReply  = (user_aac_reply*)(aBuff+sizeof(user_aac_srb32));
+
+ #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 = sizeof(user_aac_srb64) +
+                          (sizeof(user_sgentry64)*(pSrb->sg64.count-1));
+    #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 = sizeof(user_aac_srb32) +
+                          (sizeof(user_sgentry32)*(pSrb->sg32.count-1));
+    #endif
+
+  }
+
+  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 || pReply->srb_status != 0x01) {
+    if(pReply->srb_status == 0x08) {
+      return set_err(EIO, "aacraid: Device %d %d does not exist\n" ,aLun,aId );
+    }
+  return set_err((errno ? errno : EIO), "aacraid result: %d.%d = %d/%d",
+                            aLun, aId, errno,
+                            pReply->srb_status);
+  }
+  return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
 /// LSI MegaRAID support
 
 class linux_megaraid_device
@@ -2939,12 +3152,23 @@
   if (sscanf(type, "megaraid,%d", &disknum) == 1) {
     return new linux_megaraid_device(this, name, 0, disknum);
   }
+
+  //aacraid?
+  unsigned int device;
+  unsigned int host;
+  if(sscanf(type, "aacraid,%d,%d,%d", &host, &channel, &device)==3) {
+    //return new linux_aacraid_device(this,name,channel,device);
+    return get_sat_device("sat,auto",
+      new linux_aacraid_device(this, name, host, channel, 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
Index: aacraid.h
===================================================================
--- aacraid.h	(revision 0)
+++ aacraid.h	(revision 0)
@@ -0,0 +1,105 @@
+/* aacraid.h
+ * Copyright (C) 2014 Raghava Aditya <Raghava.Aditya@pmcs.com>
+ *
+ * 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
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+// Check windows
+#if _WIN32 || _WIN64
+#if _WIN64
+  #define ENVIRONMENT64
+#else
+  #define ENVIRONMENT32
+#endif
+#endif
+
+// Check GCC
+#if __GNUC__
+#if __x86_64__ || __ppc64__
+  #define ENVIRONMENT64
+#else
+  #define ENVIRONMENT32
+#endif
+#endif
+
+#define METHOD_BUFFERED 0
+#define METHOD_NEITHER  3
+
+#define CTL_CODE(function, method) ((4<< 16) | ((function) << 2) | (method) )
+
+#define FSACTL_SEND_RAW_SRB  CTL_CODE(2067, METHOD_BUFFERED)
+
+#define  SRB_FUNCTION_EXECUTE_SCSI 0X00
+
+#define  SRB_DataIn      0x0040
+#define  SRB_DataOut     0x0080
+#define  SRB_NoDataXfer  0x0000
+
+typedef struct {
+  uint32_t lo32;
+  uint32_t hi32;
+  }  address64;
+
+typedef struct {
+  address64 addr64;
+  uint32_t length;  /* Length. */
+  }  user_sgentry64;
+
+typedef struct {
+  uint32_t aadr32;
+  uint32_t length;
+  }  user_sgentry32;
+
+typedef struct {
+  uint32_t         count;
+  user_sgentry64   sg64[1];
+  }  user_sgmap64;
+
+typedef struct {
+  uint32_t         count;
+  user_sgentry32   sg32[1];
+  }  user_sgmap32;
+
+typedef struct {
+  uint32_t function;           //SRB_FUNCTION_EXECUTE_SCSI 0x00
+  uint32_t channel;            //bus
+  uint32_t id;                 //use the ID number this is wrong
+  uint32_t lun;                //Logical unit number
+  uint32_t timeout;
+  uint32_t flags;              //Interesting stuff I must say
+  uint32_t count;              // Data xfer size
+  uint32_t retry_limit;        // We shall see
+  uint32_t cdb_size;           // Length of CDB
+  uint8_t  cdb[16];            // The actual cdb command
+  user_sgmap64 sg64;           // pDatabuffer and address of Databuffer
+  }  user_aac_srb64;
+   
+typedef struct {
+  uint32_t function;           //SRB_FUNCTION_EXECUTE_SCSI 0x00
+  uint32_t channel;            //bus
+  uint32_t id;                 //use the ID number this is wrong
+  uint32_t lun;                //Logical unit number
+  uint32_t timeout;
+  uint32_t flags;              //Interesting stuff I must say
+  uint32_t count;              // Data xfer size
+  uint32_t retry_limit;        // We shall see
+  uint32_t cdb_size;           // Length of CDB
+  uint8_t  cdb[16];            // The actual cdb command
+  user_sgmap32 sg32;           // pDatabuffer and address of Databuffer
+  }  user_aac_srb32;
+
+typedef struct {
+  uint32_t status;
+  uint32_t srb_status;
+  uint32_t scsi_status;
+  uint32_t data_xfer_length;
+  uint32_t sense_data_size;
+  uint8_t  sense_data[30];
+  }  user_aac_reply;
