From 4fb1d5c0cb8c0e6e32ac5dc2271d22147ea6f697 Mon Sep 17 00:00:00 2001 From: guidog <guidog@4ea69e1a-61f1-4043-bf83-b5c94c648137> Date: Mon, 9 Oct 2006 11:45:12 +0000 Subject: [PATCH] CCISS support for Linux git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/trunk@2277 4ea69e1a-61f1-4043-bf83-b5c94c648137 --- sm5/CHANGELOG | 6 +- sm5/os_linux.cpp | 213 ++++++++++++++++++++++++++++++++++++++++++- sm5/smartctl.8.in | 18 +++- sm5/smartctl.cpp | 56 ++++++++---- sm5/smartd.8.in | 16 +++- sm5/smartd.conf.5.in | 16 +++- sm5/smartd.cpp | 120 ++++++++++++++++++------ sm5/utility.h | 3 +- 8 files changed, 381 insertions(+), 67 deletions(-) diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG index 53036f1c0..d870a6ca0 100644 --- a/sm5/CHANGELOG +++ b/sm5/CHANGELOG @@ -1,6 +1,6 @@ CHANGELOG for smartmontools -$Id: CHANGELOG,v 1.568 2006/10/08 22:50:39 pjwilliams Exp $ +$Id: CHANGELOG,v 1.569 2006/10/09 11:45:12 guidog Exp $ The most recent version of this file is: http://smartmontools.cvs.sourceforge.net/smartmontools/sm5/CHANGELOG?view=markup @@ -33,6 +33,10 @@ NOTES FOR FUTURE RELEASES: see TODO file. <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE> + [GG] Add CCISS (Compaq Smart Array Controller) support with contributions + from Praveen Chidambaram, Douglas Gilbert, Guido Guenther and Fr�d�ric + BOITEUX + [PW] Drive database: added Hitachi Deskstar T7K250 and Hitachi Deskstar 7K500 series. Thanks to L. J. Wu for providing a patch diff --git a/sm5/os_linux.cpp b/sm5/os_linux.cpp index 3deda1f36..54347ce5f 100644 --- a/sm5/os_linux.cpp +++ b/sm5/os_linux.cpp @@ -66,17 +66,22 @@ extern smartmonctrl * con; #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: os_linux.cpp,v 1.86 2006/09/12 01:16:54 sxzzsf Exp $"; +static const char *filenameandversion="$Id: os_linux.cpp,v 1.87 2006/10/09 11:45:12 guidog Exp $"; -const char *os_XXXX_c_cvsid="$Id: os_linux.cpp,v 1.86 2006/09/12 01:16:54 sxzzsf Exp $" \ +const char *os_XXXX_c_cvsid="$Id: os_linux.cpp,v 1.87 2006/10/09 11:45:12 guidog Exp $" \ ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_LINUX_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; // to hold onto exit code for atexit routine @@ -85,6 +90,23 @@ extern int exitstatus; // 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. */ @@ -193,8 +215,13 @@ int deviceopen(const char *pathname, char *type){ } return open(pathname, O_RDONLY | O_NONBLOCK); } + 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) @@ -618,6 +645,94 @@ int ata_command_interface(int device, smart_command_set command, int select, cha return 0; } +// CCISS Smart Array Controller +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; +} + +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; +} +// end CCISS Smart Array Controller + // >>>>>> Start of general SCSI specific linux code /* Linux specific code. @@ -926,7 +1041,8 @@ static int sisc_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report) * (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; @@ -956,8 +1072,94 @@ int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report) } } +/* Check and call the right interface. Maybe 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); @@ -1657,6 +1859,7 @@ static const char * lin_dev_scsi_tape2 = "os"; static const char * lin_dev_scsi_tape3 = "nos"; static const char * lin_dev_3ware_9000_char = "twa"; static const char * lin_dev_3ware_678k_char = "twe"; +static const char * lin_dev_cciss_dir = "cciss/"; int guess_device_type(const char * dev_name) { int len; @@ -1719,6 +1922,10 @@ int guess_device_type(const char * dev_name) { if (!strncmp(lin_dev_3ware_678k_char, dev_name, strlen(lin_dev_3ware_678k_char))) return CONTROLLER_3WARE_678K_CHAR; + // form /dev/cciss* + if (!strncmp(lin_dev_cciss_dir, dev_name, + strlen(lin_dev_cciss_dir))) + return CONTROLLER_CCISS; // we failed to recognize any of the forms return CONTROLLER_UNKNOWN; diff --git a/sm5/smartctl.8.in b/sm5/smartctl.8.in index 1c11629c4..ca1a9ddce 100644 --- a/sm5/smartctl.8.in +++ b/sm5/smartctl.8.in @@ -1,7 +1,7 @@ .ig Copyright (C) 2002-6 Bruce Allen <smartmontools-support@lists.sourceforge.net> - $Id: smartctl.8.in,v 1.86 2006/09/27 21:42:03 chrfranke Exp $ + $Id: smartctl.8.in,v 1.87 2006/10/09 11:45:12 guidog Exp $ 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 @@ -185,9 +185,9 @@ use the exit status of \fBsmartctl\fP (see RETURN VALUES below). .TP .B \-d TYPE, \-\-device=TYPE Specifies the type of the device. The valid arguments to this option -are \fIata\fP, \fIscsi\fP, \fIsat\fP, \fImarvell\fP, \fI3ware,N\fP, and \fIhpt,L/M\fP -or \fIhpt,L/M/N\fP. If this option is not used then \fBsmartctl\fP will attempt to -guess the device type from the device name. +are \fIata\fP, \fIscsi\fP, \fIsat\fP, \fImarvell\fP, \fI3ware,N\fP, and \fIhpt,L/M\fP, +\fIcciss,N\fP or \fIhpt,L/M/N\fP. If this option is not used then +\fBsmartctl\fP will attempt to guess the device type from the device name. The \'sat\' device type is for ATA disks that have a SCSI to ATA Translation (SAT) Layer (SATL) between the disk and the operating system. @@ -291,6 +291,8 @@ these values are limited by the model of the HighPoint RocketRAID controller. .B HighPoint RocketRAID controllers are currently ONLY supported under Linux. +.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 @@ -1242,6 +1244,12 @@ these LBAs have been tested, read\-scan the remainder of the disk. If the disk 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 @@ -1369,7 +1377,7 @@ these documents may be found in the References section of the .SH CVS ID OF THIS PAGE: -$Id: smartctl.8.in,v 1.86 2006/09/27 21:42:03 chrfranke Exp $ +$Id: smartctl.8.in,v 1.87 2006/10/09 11:45:12 guidog Exp $ .\" Local Variables: .\" mode: nroff .\" End: diff --git a/sm5/smartctl.cpp b/sm5/smartctl.cpp index 44591983e..051824d8e 100644 --- a/sm5/smartctl.cpp +++ b/sm5/smartctl.cpp @@ -50,7 +50,7 @@ extern const char *os_solaris_ata_s_cvsid; #endif extern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *scsiprint_c_cvsid, *utility_c_cvsid; -const char* smartctl_c_cvsid="$Id: smartctl.cpp,v 1.155 2006/09/20 16:17:31 shattered Exp $" +const char* smartctl_c_cvsid="$Id: smartctl.cpp,v 1.156 2006/10/09 11:45:12 guidog Exp $" ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID KNOWNDRIVES_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID; // This is a block containing all the "control variables". We declare @@ -239,7 +239,7 @@ const char *getvalidarglist(char opt) { case 'q': return "errorsonly, silent"; case 'd': - return "ata, scsi, marvell, sat, 3ware,N, hpt,L/M/N"; + return "ata, scsi, marvell, sat, 3ware,N, hpt,L/M/N cciss,N"; case 'T': return "normal, conservative, permissive, verypermissive"; case 'b': @@ -459,21 +459,35 @@ void ParseOpts (int argc, char** argv){ 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")) { @@ -948,6 +962,9 @@ int main (int argc, char **argv){ case CONTROLLER_3WARE_678K_CHAR: mode="ATA_3WARE_678K"; break; + case CONTROLLER_CCISS: + mode="CCISS"; + break; default: mode="ATA"; break; @@ -981,6 +998,11 @@ int main (int argc, char **argv){ if ((0 == retval) && (CONTROLLER_SAT == con->controller_type)) retval = ataPrintMain(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; diff --git a/sm5/smartd.8.in b/sm5/smartd.8.in index 907ccd5c0..928c5e239 100644 --- a/sm5/smartd.8.in +++ b/sm5/smartd.8.in @@ -1,7 +1,7 @@ .ig Copyright (C) 2002-6 Bruce Allen <smartmontools-support@lists.sourceforge.net> -$Id: smartd.8.in,v 1.106 2006/09/27 21:42:03 chrfranke Exp $ +$Id: smartd.8.in,v 1.107 2006/10/09 11:45:12 guidog Exp $ 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 @@ -619,8 +619,8 @@ directives can be used for these disks (but see note below). .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, \fIsat\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\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 @@ -699,8 +699,14 @@ Alternatively use the character device interfaces /dev/twe0-15 (3ware 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 hpt,L/M/N \- the device consists of one or more ATA disks connected to a HighPoint @@ -1929,4 +1935,4 @@ smartmontools home page at \fBhttp://smartmontools.sourceforge.net/#references\f .SH CVS ID OF THIS PAGE: -$Id: smartd.8.in,v 1.106 2006/09/27 21:42:03 chrfranke Exp $ +$Id: smartd.8.in,v 1.107 2006/10/09 11:45:12 guidog Exp $ diff --git a/sm5/smartd.conf.5.in b/sm5/smartd.conf.5.in index f0819a95f..9378c2639 100644 --- a/sm5/smartd.conf.5.in +++ b/sm5/smartd.conf.5.in @@ -1,7 +1,7 @@ .ig Copyright (C) 2002-6 Bruce Allen <smartmontools-support@lists.sourceforge.net> -$Id: smartd.conf.5.in,v 1.77 2006/09/15 08:01:20 sxzzsf Exp $ +$Id: smartd.conf.5.in,v 1.78 2006/10/09 11:45:12 guidog Exp $ 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 @@ -254,8 +254,8 @@ directives can be used for these disks (but see note below). .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, \fIsat\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 @@ -334,8 +334,14 @@ Alternatively use the character device interfaces /dev/twe0-15 (3ware 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 hpt,L/M/N \- the device consists of one or more ATA disks connected to a HighPoint @@ -1334,4 +1340,4 @@ SEE ALSO: .SH CVS ID OF THIS PAGE: -$Id: smartd.conf.5.in,v 1.77 2006/09/15 08:01:20 sxzzsf Exp $ +$Id: smartd.conf.5.in,v 1.78 2006/10/09 11:45:12 guidog Exp $ diff --git a/sm5/smartd.cpp b/sm5/smartd.cpp index 05725c497..b10e6e0b3 100644 --- a/sm5/smartd.cpp +++ b/sm5/smartd.cpp @@ -115,14 +115,14 @@ extern "C" int getdomainname(char *, int); // no declaration in header files! extern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *escalade_c_cvsid, *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *utility_c_cvsid; -static const char *filenameandversion="$Id: smartd.cpp,v 1.378 2006/09/20 16:17:31 shattered Exp $"; +static const char *filenameandversion="$Id: smartd.cpp,v 1.379 2006/10/09 11:45:12 guidog Exp $"; #ifdef NEED_SOLARIS_ATA_CODE extern const char *os_solaris_ata_s_cvsid; #endif #ifdef _WIN32 extern const char *daemon_win32_c_cvsid, *hostname_win32_c_cvsid, *syslog_win32_c_cvsid; #endif -const char *smartd_c_cvsid="$Id: smartd.cpp,v 1.378 2006/09/20 16:17:31 shattered Exp $" +const char *smartd_c_cvsid="$Id: smartd.cpp,v 1.379 2006/10/09 11:45:12 guidog Exp $" ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID #ifdef DAEMON_WIN32_H_CVSID DAEMON_WIN32_H_CVSID @@ -712,6 +712,18 @@ void MailWarning(cfgfile *cfg, int which, char *fmt, ...){ *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); @@ -723,9 +735,11 @@ void MailWarning(cfgfile *cfg, int which, char *fmt, ...){ case CONTROLLER_SCSI: exportenv(environ_strings[8], "SMARTD_DEVICETYPE", "scsi"); exportenv(environ_strings[9], "SMARTD_DEVICE", cfg->name); + break; case CONTROLLER_SAT: exportenv(environ_strings[8], "SMARTD_DEVICETYPE", "sat"); exportenv(environ_strings[9], "SMARTD_DEVICE", cfg->name); + break; case CONTROLLER_HPT: { char *s,devicetype[16]; @@ -738,6 +752,7 @@ void MailWarning(cfgfile *cfg, int which, char *fmt, ...){ if (s) *s=' '; } + break; } snprintf(fullmessage, 1024, @@ -1090,7 +1105,7 @@ void PrintHead(){ void Directives() { PrintOut(LOG_INFO, "Configuration file (%s) Directives (after device name):\n" - " -d TYPE Set the device type: ata, scsi, marvell, removable, sat, 3ware,N, hpt,L/M/N\n" + " -d TYPE Set the device type: ata, scsi, marvell, removable, sat, 3ware,N, hpt,L/M/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" @@ -1638,18 +1653,26 @@ static int SCSIDeviceScan(cfgfile *cfg, int scanning) { char *device = cfg->name; struct scsi_iec_mode_page iec; UINT8 tBuf[64]; + char *mode=NULL; // should we try to register this as a SCSI device? switch (cfg->controller_type) { case CONTROLLER_SCSI: case CONTROLLER_UNKNOWN: + mode="SCSI"; + break; + case CONTROLLER_CCISS: + mode="CCISS"; 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) + if ((fd = OpenDevice(device, mode, scanning)) < 0) return 1; PrintOut(LOG_INFO,"Device: %s, opened\n", device); @@ -1725,7 +1748,8 @@ static int SCSIDeviceScan(cfgfile *cfg, int scanning) { } // record type of device - cfg->controller_type = CONTROLLER_SCSI; + if (cfg->controller_type == CONTROLLER_UNKNOWN) + cfg->controller_type = CONTROLLER_SCSI; // get rid of allocated memory only needed for ATA devices. These // might have been allocated if the user specified Ignore options or @@ -2525,6 +2549,24 @@ int SCSICheckDevice(cfgfile *cfg) int fd; char *name=cfg->name; const char *cp; + char *mode=NULL; + + // should we try to register this as a SCSI device? + switch (cfg->controller_type) { + case CONTROLLER_CCISS: + mode="CCISS"; + break; + case CONTROLLER_SCSI: + case CONTROLLER_UNKNOWN: + mode="SCSI"; + 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; // If the user has asked for it, test the email warning system if (cfg->mailwarn && cfg->mailwarn->emailtest) @@ -2532,7 +2574,7 @@ int SCSICheckDevice(cfgfile *cfg) // if we can't open device, fail gracefully rather than hard -- // perhaps the next time around we'll be able to open it - if ((fd=OpenDevice(name, "SCSI", 0))<0) { + if ((fd=OpenDevice(name, mode, 0))<0) { // Lack of PrintOut() here is intentional! MailWarning(cfg, 9, "Device: %s, unable to open device", name); return 1; @@ -2993,26 +3035,42 @@ int ParseToken(char *token,cfgfile *cfg){ 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': @@ -3429,13 +3487,13 @@ int ParseConfigLine(int entry, int lineno,char *line){ } } - // 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; } @@ -3446,7 +3504,8 @@ int ParseConfigLine(int entry, int lineno,char *line){ } // 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; @@ -4116,7 +4175,7 @@ void RegisterDevices(int scanning){ 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 { @@ -4129,7 +4188,8 @@ void RegisterDevices(int scanning){ } // 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 diff --git a/sm5/utility.h b/sm5/utility.h index 2b23d51e0..3c21e2890 100644 --- a/sm5/utility.h +++ b/sm5/utility.h @@ -25,7 +25,7 @@ #ifndef UTILITY_H_ #define UTILITY_H_ -#define UTILITY_H_CVSID "$Id: utility.h,v 1.46 2006/08/25 06:06:25 sxzzsf Exp $\n" +#define UTILITY_H_CVSID "$Id: utility.h,v 1.47 2006/10/09 11:45:12 guidog Exp $\n" #include <time.h> #include <sys/types.h> // for regex.h (according to POSIX) @@ -186,5 +186,6 @@ void MsecToText(unsigned int msec, char *txt); #define CONTROLLER_MARVELL_SATA 0x07 // SATA drives behind Marvell controllers #define CONTROLLER_SAT 0x08 // SATA device behind a SCSI ATA Translation (SAT) layer #define CONTROLLER_HPT 0x09 // SATA drives behind HighPoint Raid controllers +#define CONTROLLER_CCISS 0x10 // CCISS controller #endif -- GitLab