Blob Blame History Raw
Patch for smartmontools >= 5.36, which adds CCISS support (for Compaq and HP Smart Arrays)
to smartctl and smartd.

The initial version was published on 2005-07-22 at the smartmontools-support mailing list
at sourceforge.net: http://article.gmane.org/gmane.linux.utilities.smartmontools/2933

Thanks to all contributors:

 - Praveen Chidambaram <bunchofmails@gmail.com> (original smartctl patch)
 - Guido Guenther <agx@debian.org> (Debian smartmontools package maintainer)
 - Frédéric Boiteux <fboiteux@calistel.com> (fixes and patch applying)
 - Douglas Gilbert <dougg@torque.net> (update to be less intrusive)

How to use smartctl for cciss devices after applying this patch? Well, for example just do:

 $ smartctl -a -d cciss,0 /dev/cciss/c0d0
 $ smartctl -H -d cciss,0 /dev/cciss/c0d0

This patch was merged by Robert Scheck <cciss@robert-scheck.de> and successfully tested on
a Linux 2.6.16 kernel.

Have a lot of fun...

--- smartmontools-5.36/os_linux.c			2006-04-12 19:02:19.000000000 +0200
+++ smartmontools-5.36/os_linux.c.cciss			2006-05-10 15:53:35.000000000 +0200
@@ -64,12 +64,17 @@
 #include "os_linux.h"
 #include "scsicmds.h"
 #include "utility.h"
+#include "extern.h"
+
+#include <linux/cciss_ioctl.h>
+
 
 #ifndef ENOTSUP
 #define ENOTSUP ENOSYS
 #endif
 typedef unsigned long long u8;
 
+
 #define ARGUSED(x) ((void)(x))
 
 static const char *filenameandversion="$Id: smartmontools-5.36-cciss.patch,v 1.1 2006/05/11 07:54:10 tmraz Exp $";
@@ -83,6 +88,23 @@
 // global variable holding byte count of allocated memory
 extern long long bytes;
 
+/* for passing global control variables */
+extern smartmonctrl *con;
+
+static int cciss_io_interface(int device, int target,
+			      struct scsi_cmnd_io * iop, int report);
+
+typedef struct _ReportLUNdata_struct
+{
+  BYTE LUNListLength[4];
+  DWORD reserved;
+  BYTE LUN[CISS_MAX_LUN][8];
+} ReportLunData_struct;
+
+/* Structure/defines of Report Physical LUNS of drive */
+#define CISS_MAX_LUN        16
+#define CISS_MAX_PHYS_LUN   1024
+#define CISS_REPORT_PHYS    0xc3
 
 
 /* This function will setup and fix device nodes for a 3ware controller. */
@@ -191,8 +213,15 @@
     }
     return open(pathname, O_RDONLY | O_NONBLOCK);
   }
+  // cciss+
+  else if(!strcmp(type, "CCISS"))
+  {
+    // the device is a cciss smart array device.
+    return open(pathname, O_RDWR | O_NONBLOCK);
+  }
   else
     return -1;
+
 }
 
 // equivalent to close(file descriptor)
@@ -609,6 +638,93 @@
   
   return 0; 
 }
+// cciss+
+static int cciss_sendpassthru(unsigned int cmdtype, unsigned char *CDB,
+    			unsigned int CDBlen, char *buff,
+    			unsigned int size, unsigned int LunID,
+    			unsigned char *scsi3addr, int fd)
+{
+    int err ;
+    IOCTL_Command_struct iocommand;
+
+    memset(&iocommand, 0, sizeof(iocommand));
+
+    if (cmdtype == 0) 
+    {
+        // To controller; nothing to do
+    }
+    else if (cmdtype == 1) 
+    {
+        iocommand.LUN_info.LogDev.VolId = LunID;
+        iocommand.LUN_info.LogDev.Mode = 1;
+    }
+    else if (cmdtype == 2) 
+    {
+        memcpy(&iocommand.LUN_info.LunAddrBytes,scsi3addr,8);
+        iocommand.LUN_info.LogDev.Mode = 0;
+    }
+    else 
+    {
+        fprintf(stderr, "cciss_sendpassthru: bad cmdtype\n");
+        return 1;
+    }
+
+    memcpy(&iocommand.Request.CDB[0], CDB, CDBlen);
+    iocommand.Request.CDBLen = CDBlen;
+    iocommand.Request.Type.Type = TYPE_CMD;
+    iocommand.Request.Type.Attribute = ATTR_SIMPLE;
+    iocommand.Request.Type.Direction = XFER_READ;
+    iocommand.Request.Timeout = 0;
+
+    iocommand.buf_size = size;
+    iocommand.buf = (unsigned char *)buff;
+
+    if ((err = ioctl(fd, CCISS_PASSTHRU, &iocommand))) 
+    {
+        fprintf(stderr, "CCISS ioctl error %d\n", err);
+    }
+    return err;
+}
+
+// cciss+
+static int cciss_getlun(int device, int target, unsigned char *physlun)
+{
+    unsigned char CDB[16]= {0};
+    ReportLunData_struct *luns;
+    int reportlunsize = sizeof(*luns) + CISS_MAX_PHYS_LUN * 8;
+    int i;
+    int ret;
+
+    luns = (ReportLunData_struct *)malloc(reportlunsize);
+
+    memset(luns, 0, reportlunsize);
+
+    /* Get Physical LUN Info (for physical device) */
+    CDB[0] = CISS_REPORT_PHYS;
+    CDB[6] = (reportlunsize >> 24) & 0xFF;  /* MSB */
+    CDB[7] = (reportlunsize >> 16) & 0xFF;
+    CDB[8] = (reportlunsize >> 8) & 0xFF;
+    CDB[9] = reportlunsize & 0xFF;
+
+    if ((ret = cciss_sendpassthru(0, CDB, 12, (char *)luns, reportlunsize, 0, NULL, device)))
+    {
+        free(luns);
+        return ret;
+    }
+
+    for (i=0; i<CISS_MAX_LUN+1; i++) 
+    {
+        if (luns->LUN[i][6] == target) 
+        {
+            memcpy(physlun, luns->LUN[i], 8);
+            free(luns);
+            return 0;
+        }
+    }
+
+    free(luns);
+    return ret;
+}
 
 // >>>>>> Start of general SCSI specific linux code
 
@@ -913,7 +1029,8 @@
  * (e.g. CHECK CONDITION). If the SCSI command could not be issued
  * (e.g. device not present or timeout) or some other problem
  * (e.g. timeout) then returns a negative errno value */
-int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report)
+static int do_normal_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop,
+                                  int report)
 {
     int res;
 
@@ -937,15 +1054,104 @@
     case SG_IO_PRESENT_YES:
 	return sg_io_cmnd_io(dev_fd, iop, report, 0);
     default:
-	pout(">>>> do_scsi_cmnd_io: bad sg_io_state=%d\n", sg_io_state); 
+	pout(">>>> do_normal_scsi_cmnd_io: bad sg_io_state=%d\n",
+             sg_io_state); 
 	sg_io_state = SG_IO_PRESENT_UNKNOWN;
         return -EIO; 	/* report error and reset state */
     }
 }
 
+// Check and call the right interface. May be when the do_generic_scsi_cmd_io interface is better
+// we can take off this crude way of calling the right interface
+
+int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report)
+{
+    switch(con->controller_type)
+    {
+        case CONTROLLER_CCISS:
+            return cciss_io_interface(dev_fd, con->controller_port-1, iop, report);
+            // not reached
+            break;
+        default:
+            return do_normal_scsi_cmnd_io(dev_fd, iop, report);
+            // not reached
+            break;
+    }
+}
+
+
 // >>>>>> End of general SCSI specific linux code
 
 
+// cciss+ >> CCSISS I/O passthrough
+// This is an interface that uses the cciss passthrough to talk to the SMART controller on
+// the HP system. The cciss driver provides a way to send SCSI cmds through the CCISS passthrough
+// essentially the methods above and below pertain to SCSI, except for the SG driver which is not
+// involved. The CCISS driver does not engage the scsi subsystem.
+static int cciss_io_interface(int device, int target, struct scsi_cmnd_io * iop, int report)
+{
+    unsigned char pBuf[512] = {0};
+    unsigned char phylun[1024] = {0};
+    int iBufLen = 512;
+    int status = -1;
+    int len = 0; // used later in the code.
+    report = 0;
+
+    cciss_getlun(device, target, phylun);
+    status = cciss_sendpassthru( 2, iop->cmnd, iop->cmnd_len, (char*) pBuf, iBufLen, 1, phylun, device);
+
+    if (0 == status)
+    {
+        if (report > 0)
+            printf("  status=0\n");
+        if (DXFER_FROM_DEVICE == iop->dxfer_dir)
+        {
+            memcpy(iop->dxferp, pBuf, iop->dxfer_len);
+            if (report > 1)
+            {
+                int trunc = (iop->dxfer_len > 256) ? 1 : 0;
+                printf("  Incoming 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);
+            }
+        }
+        return 0;
+    }
+    iop->scsi_status = status & 0x7e; /* bits 0 and 7 used to be for vendors */
+    if (LSCSI_DRIVER_SENSE == ((status >> 24) & 0xf))
+        iop->scsi_status = SCSI_STATUS_CHECK_CONDITION;
+    len = (SEND_IOCTL_RESP_SENSE_LEN < iop->max_sense_len) ?
+               SEND_IOCTL_RESP_SENSE_LEN : iop->max_sense_len;
+    if ((SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) &&
+        iop->sensep && (len > 0))
+    {
+        memcpy(iop->sensep, pBuf, len);
+        iop->resp_sense_len = iBufLen;
+        if (report > 1)
+        {
+            printf("  >>> Sense buffer, len=%d:\n", (int)len);
+            dStrHex((const char *)pBuf, len , 1);
+        }
+    }
+    if (report)
+    {
+        if (SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) {
+            printf("  status=%x: sense_key=%x asc=%x ascq=%x\n", status & 0xff,
+                 pBuf[2] & 0xf, pBuf[12], pBuf[13]);
+        }
+        else
+            printf("  status=0x%x\n", status);
+    }
+    if (iop->scsi_status > 0)
+        return 0;
+    else
+    {
+        if (report > 0)
+            printf("  ioctl status=0x%x but scsi status=0, fail with EIO\n", status);
+        return -EIO;      /* give up, assume no device there */
+    }
+} 
+
 // prototype
 void printwarning(smart_command_set command);
 
--- smartmontools-5.36/smartctl.8.in			2006-04-12 17:45:38.000000000 +0200
+++ smartmontools-5.36/smartctl.8.in.cciss		2006-05-10 15:53:35.000000000 +0200
@@ -177,7 +177,7 @@
 .TP
 .B \-d TYPE, \-\-device=TYPE
 Specifies the type of the device.  The valid arguments to this option
-are \fIata\fP, \fIscsi\fP, \fImarvell\fP, and \fI3ware,N\fP. If this option is not
+are \fIata\fP, \fIscsi\fP, \fImarvell\fP, \fIcciss,N\fP and \fI3ware,N\fP. If this option is not
 used then \fBsmartctl\fP will attempt to guess the device type from
 the device name.
 
@@ -257,6 +257,8 @@
 
 .B 3ware controllers are currently ONLY supported under Linux and FreeBSD.
 
+.B cciss controllers are currently ONLY supported under Linux.
+
 .TP
 .B \-T TYPE, \-\-tolerance=TYPE
 Specifies how tolerant \fBsmartctl\fP should be of ATA and SMART command
@@ -1157,6 +1159,12 @@
 power\-cycled during the read\-scan, resume the scan 45 minutes after power to the
 device is restored.
 .PP
+.nf
+.B smartctl \-a \-d cciss,0 /dev/cciss/c0d0
+.fi
+Examine all SMART data for the first SCSI disk connected to a cciss
+RAID controller card.
+.PP
 .SH RETURN VALUES
 The return values of \fBsmartctl\fP are defined by a bitmask.  If all
 is well with the disk, the return value (exit status) of
--- smartmontools-5.36/smartctl.c			2006-04-12 16:54:28.000000000 +0200
+++ smartmontools-5.36/smartctl.c.cciss			2006-05-10 15:53:35.000000000 +0200
@@ -234,7 +234,7 @@
   case 'q':
     return "errorsonly, silent";
   case 'd':
-    return "ata, scsi, marvell, 3ware,N";
+    return "ata, scsi, marvell, 3ware,N, cciss,N";
   case 'T':
     return "normal, conservative, permissive, verypermissive";
   case 'b':
@@ -384,21 +384,35 @@
           con->dont_print = FALSE;
           pout("No memory for argument of -d. Exiting...\n");
           exit(FAILCMD);
-        } else if (strncmp(s,"3ware,",6)) {
-          badarg = TRUE;
-        } else if (split_report_arg2(s, &i)) {
-          sprintf(extraerror, "Option -d 3ware,N requires N to be a non-negative integer\n");
-          badarg = TRUE;
-        } else if (i<0 || i>15) {
-          sprintf(extraerror, "Option -d 3ware,N (N=%d) must have 0 <= N <= 15\n", i);
-          badarg = TRUE;
-        } else {
-	  // NOTE: controller_port == disk number + 1
-	  con->controller_type = CONTROLLER_3WARE;
-          con->controller_port = i+1;
-        }
-        free(s);
-      }         
+        } else if (!strncmp(s,"3ware,",6)) {
+            if (split_report_arg2(s, &i)) {
+                sprintf(extraerror, "Option -d 3ware,N requires N to be a non-negative integer\n");
+                badarg = TRUE;
+            } else if (i<0 || i>15) {
+                sprintf(extraerror, "Option -d 3ware,N (N=%d) must have 0 <= N <= 15\n", i);
+                badarg = TRUE;
+            } else {
+	        // NOTE: controller_port == disk number + 1
+	        con->controller_type = CONTROLLER_3WARE;
+                con->controller_port = i+1;
+            }
+	    free(s);
+        } else if (!strncmp(s,"cciss,",6)) {
+            if (split_report_arg2(s, &i)) {
+                sprintf(extraerror, "Option -d cciss,N requires N to be a non-negative integer\n");
+                badarg = TRUE;
+            } else if (i<0 || i>15) {
+                sprintf(extraerror, "Option -d cciss,N (N=%d) must have 0 <= N <= 15\n", i);
+                badarg = TRUE;
+            } else {
+              // NOTE: controller_port == drive number
+              con->controller_type = CONTROLLER_CCISS;
+              con->controller_port = i+1;
+            }
+            free(s);
+        } else
+	    badarg=TRUE;
+      }
       break;
     case 'T':
       if (!strcmp(optarg,"normal")) {
@@ -856,6 +870,9 @@
   case CONTROLLER_3WARE_678K_CHAR:
     mode="ATA_3WARE_678K";
     break;
+  case CONTROLLER_CCISS:
+    mode="CCISS";
+    break;
   default:
     mode="ATA";
     break;
@@ -887,6 +904,11 @@
   case CONTROLLER_SCSI:
     retval = scsiPrintMain(fd);
     break;
+  case CONTROLLER_CCISS:
+    // route the cciss command through scsiPrintMain. 
+    // cciss pass-throughs will separeate from the SCSI data-path.
+    retval = scsiPrintMain(fd);
+    break;
   default:
     retval = ataPrintMain(fd);
     break;
--- smartmontools-5.36/smartd.8.in			2006-04-12 15:55:44.000000000 +0200
+++ smartmontools-5.36/smartd.8.in.cciss		2006-05-10 15:53:35.000000000 +0200
@@ -596,8 +596,8 @@
 .B \-d TYPE
 Specifies the type of the device.  This Directive may be used multiple
 times for one device, but the arguments \fIata\fP, \fIscsi\fP,
-\fImarvell\fP, and \fI3ware,N\fP are mutually-exclusive. If more than
-one is given then \fBsmartd\fP will use the last one which appears.
+\fImarvell\fP, \fIcciss,N\fP and \fI3ware,N\fP are mutually-exclusive. If more
+than one is given then \fBsmartd\fP will use the last one which appears.
 
 If none of these three arguments is given, then \fBsmartd\fP will
 first attempt to guess the device type by looking at whether the sixth
@@ -664,8 +664,14 @@
 6/7/8000 series controllers) or /dev/twa0-15 (3ware 9000 series
 controllers).
 
+.I cciss,N
+\- the device consists of one or more SCSI disks connected to a cciss
+RAID controller. The non-negative integer N (in the range from 0 to 15
+inclusive) denotes which disk on the controller is monitored.  In log
+files and email messages this disk will be identified as cciss_disk_XX
+with XX in the range from 00 to 15 inclusive.
 
-.B 3ware controllers are currently ONLY supported under Linux.
+.B 3ware and cciss controllers are currently ONLY supported under Linux.
 
 .I removable
 \- the device or its media is removable.  This indicates to
--- smartmontools-5.36/smartd.c				2006-04-12 18:18:57.000000000 +0200
+++ smartmontools-5.36/smartd.c.cciss			2006-05-10 15:53:35.000000000 +0200
@@ -711,6 +711,18 @@
 	*s=' ';
     }
     break;
+  case CONTROLLER_CCISS:
+    {
+      char *s,devicetype[16];
+      sprintf(devicetype, "cciss,%d", cfg->controller_port-1);
+      exportenv(environ_strings[8], "SMARTD_DEVICETYPE", devicetype);
+      if ((s=strchr(cfg->name, ' ')))
+	*s='\0';
+      exportenv(environ_strings[9], "SMARTD_DEVICE", cfg->name);
+      if (s)
+	*s=' ';
+    }
+    break;
   case CONTROLLER_ATA:
     exportenv(environ_strings[8], "SMARTD_DEVICETYPE", "ata");
     exportenv(environ_strings[9], "SMARTD_DEVICE", cfg->name);
@@ -722,6 +734,7 @@
   case CONTROLLER_SCSI:
     exportenv(environ_strings[8], "SMARTD_DEVICETYPE", "scsi");
     exportenv(environ_strings[9], "SMARTD_DEVICE", cfg->name);
+    break;
   }
 
   snprintf(fullmessage, 1024,
@@ -1074,7 +1087,7 @@
 void Directives() {
   PrintOut(LOG_INFO,
            "Configuration file (%s) Directives (after device name):\n"
-           "  -d TYPE Set the device type: ata, scsi, marvell, removable, 3ware,N\n"
+           "  -d TYPE Set the device type: ata, scsi, marvell, removable, 3ware,N, cciss,N\n"
            "  -T TYPE Set the tolerance to one of: normal, permissive\n"
            "  -o VAL  Enable/disable automatic offline tests (on/off)\n"
            "  -S VAL  Enable/disable attribute autosave (on/off)\n"
@@ -1607,11 +1620,15 @@
   // should we try to register this as a SCSI device?
   switch (cfg->controller_type) {
   case CONTROLLER_SCSI:
+  case CONTROLLER_CCISS:
   case CONTROLLER_UNKNOWN:
     break;
   default:
     return 1;
   }
+  // pass user settings on to low-level SCSI commands
+  con->controller_port=cfg->controller_port;
+  con->controller_type=cfg->controller_type;
   
   // open the device
   if ((fd = OpenDevice(device, "SCSI", scanning)) < 0)
@@ -2796,26 +2813,42 @@
         PrintOut(LOG_CRIT,
                  "No memory to copy argument to -d option - exiting\n");
         EXIT(EXIT_NOMEM);
-      } else if (strncmp(s,"3ware,",6)) {
-        badarg=1;
-      } else if (split_report_arg2(s, &i)){
-        PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive -d 3ware,N requires N integer\n",
-                 configfile, lineno, name);
-        badarg=1;
-      } else if ( i<0 || i>15) {
-        PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive -d 3ware,N (N=%d) must have 0 <= N <= 15\n",
-                 configfile, lineno, name, i);
-        badarg=1;
-      } else {
-	// determine type of escalade device from name of device
-	cfg->controller_type = guess_device_type(name);
-	if (cfg->controller_type!=CONTROLLER_3WARE_9000_CHAR && cfg->controller_type!=CONTROLLER_3WARE_678K_CHAR)
-	  cfg->controller_type=CONTROLLER_3WARE_678K;
+      } else if (!strncmp(s,"3ware,",6)) {
+          if (split_report_arg2(s, &i)){
+              PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive -d 3ware,N requires N integer\n",
+               	       configfile, lineno, name);
+              badarg=1;
+          } else if ( i<0 || i>15) {
+              PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive -d 3ware,N (N=%d) must have 0 <= N <= 15\n",
+                       configfile, lineno, name, i);
+              badarg=1;
+          } else {
+	      // determine type of escalade device from name of device
+	      cfg->controller_type = guess_device_type(name);
+	      if (cfg->controller_type!=CONTROLLER_3WARE_9000_CHAR && cfg->controller_type!=CONTROLLER_3WARE_678K_CHAR)
+	           cfg->controller_type=CONTROLLER_3WARE_678K;
 	    
-        // NOTE: controller_port == disk number + 1
-        cfg->controller_port = i+1;
+              // NOTE: controller_port == disk number + 1
+              cfg->controller_port = i+1;
+          }
+      } else if (!strncmp(s,"cciss,",6)) {
+          if (split_report_arg2(s, &i)){
+              PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive -d cciss,N requires N integer\n",
+               	       configfile, lineno, name);
+              badarg=1;
+          } else if ( i<0 || i>15) {
+              PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive -d cciss,N (N=%d) must have 0 <= N <= 15\n",
+                       configfile, lineno, name, i);
+              badarg=1;
+          } else {
+              // NOTE: controller_port == disk number + 1
+              cfg->controller_type = CONTROLLER_CCISS;
+              cfg->controller_port = i+1;
+          }
+      } else {
+          badarg=1;
       }
-      s=CheckFree(s, __LINE__,filenameandversion); 
+      s=CheckFree(s, __LINE__,filenameandversion);
     }
     break;
   case 'F':
@@ -3223,13 +3256,13 @@
     }
   }
   
-  // If we found 3ware controller, then modify device name by adding a SPACE
-  if (cfg->controller_port){
+  // If we found 3ware/cciss controller, then modify device name by adding a SPACE
+  if (cfg->controller_port) {
     int len=17+strlen(cfg->name);
     char *newname;
     
     if (devscan){
-      PrintOut(LOG_CRIT, "smartd: can not scan for 3ware devices (line %d of file %s)\n",
+      PrintOut(LOG_CRIT, "smartd: can not scan for 3ware/cciss devices (line %d of file %s)\n",
                lineno, configfile);
       return -2;
     }
@@ -3240,7 +3273,8 @@
     }
     
     // Make new device name by adding a space then RAID disk number
-    snprintf(newname, len, "%s [3ware_disk_%02d]", cfg->name, cfg->controller_port-1);
+    snprintf(newname, len, "%s [%s_disk_%02d]", cfg->name, (cfg->controller_type == CONTROLLER_CCISS) ? "cciss" : "3ware", 
+		                                cfg->controller_port-1);
     cfg->name=CheckFree(cfg->name, __LINE__,filenameandversion);
     cfg->name=newname;
     bytes+=16;
@@ -3886,7 +3920,7 @@
       continue;
     
     // register ATA devices
-    if (ent->controller_type!=CONTROLLER_SCSI){
+    if (ent->controller_type!=CONTROLLER_SCSI && ent->controller_type!=CONTROLLER_CCISS){
       if (ATADeviceScan(ent, scanning))
         CanNotRegister(ent->name, "ATA", ent->lineno, scanning);
       else {
@@ -3899,7 +3933,8 @@
     }
     
     // then register SCSI devices
-    if (ent->controller_type==CONTROLLER_SCSI || ent->controller_type==CONTROLLER_UNKNOWN){
+    if (ent->controller_type==CONTROLLER_SCSI || ent->controller_type==CONTROLLER_CCISS || 
+        ent->controller_type==CONTROLLER_UNKNOWN){
       int retscsi=0;
 
 #if SCSITIMEOUT
--- smartmontools-5.36/smartd.conf.5.in			2006-04-12 16:03:14.000000000 +0200
+++ smartmontools-5.36/smartd.conf.5.in.cciss		2006-05-10 15:53:35.000000000 +0200
@@ -235,8 +235,8 @@
 .B \-d TYPE
 Specifies the type of the device.  This Directive may be used multiple
 times for one device, but the arguments \fIata\fP, \fIscsi\fP,
-\fImarvell\fP, and \fI3ware,N\fP are mutually-exclusive. If more than
-one is given then \fBsmartd\fP will use the last one which appears.
+\fImarvell\fP, \fIcciss,N\fP and \fI3ware,N\fP are mutually-exclusive. If more
+than one is given then \fBsmartd\fP will use the last one which appears.
 
 If none of these three arguments is given, then \fBsmartd\fP will
 first attempt to guess the device type by looking at whether the sixth
@@ -303,8 +303,14 @@
 6/7/8000 series controllers) or /dev/twa0-15 (3ware 9000 series
 controllers).
 
+.I cciss,N
+\- the device consists of one or more SCSI disks connected to a cciss
+RAID controller. The non-negative integer N (in the range from 0 to 15
+inclusive) denotes which disk on the controller is monitored.  In log
+files and email messages this disk will be identified as cciss_disk_XX
+with XX in the range from 00 to 15 inclusive.
 
-.B 3ware controllers are currently ONLY supported under Linux.
+.B 3ware and cciss controllers are currently ONLY supported under Linux.
 
 .I removable
 \- the device or its media is removable.  This indicates to
--- smartmontools-5.36/utility.h			2006-04-12 16:54:28.000000000 +0200
+++ smartmontools-5.36/utility.h.cciss			2006-05-10 15:53:35.000000000 +0200
@@ -174,6 +174,6 @@
 #define CONTROLLER_3WARE_9000_CHAR      0x05  // set by guess_device_type()
 #define CONTROLLER_3WARE_678K_CHAR      0x06  // set by guess_device_type()
 #define CONTROLLER_MARVELL_SATA         0x07  // SATA drives behind Marvell controllers
-
+#define CONTROLLER_CCISS		0x08  // CCISS controller 
 
 #endif