aboutsummaryrefslogtreecommitdiffstats
path: root/sysutils
diff options
context:
space:
mode:
authorpav <pav@FreeBSD.org>2007-03-03 21:05:41 +0800
committerpav <pav@FreeBSD.org>2007-03-03 21:05:41 +0800
commita219498843254bf5e492ae79d4bf6d595618e775 (patch)
tree25025478ed8c66164bad39e499fc1c5eb5cb2a5b /sysutils
parent2efd40e1a83bb8a06ac8c79055929e93f94161fb (diff)
downloadfreebsd-ports-gnome-a219498843254bf5e492ae79d4bf6d595618e775.tar.gz
freebsd-ports-gnome-a219498843254bf5e492ae79d4bf6d595618e775.tar.zst
freebsd-ports-gnome-a219498843254bf5e492ae79d4bf6d595618e775.zip
- Add optional ciss(4) support, defaults to off
Submitted by: mi
Diffstat (limited to 'sysutils')
-rw-r--r--sysutils/smartmontools-devel/Makefile14
-rw-r--r--sysutils/smartmontools-devel/files/ciss-patch172
-rw-r--r--sysutils/smartmontools-devel/files/ciss_common.c197
-rw-r--r--sysutils/smartmontools/Makefile14
-rw-r--r--sysutils/smartmontools/files/ciss-patch172
-rw-r--r--sysutils/smartmontools/files/ciss_common.c197
6 files changed, 764 insertions, 2 deletions
diff --git a/sysutils/smartmontools-devel/Makefile b/sysutils/smartmontools-devel/Makefile
index 189dc559c37e..158c22081338 100644
--- a/sysutils/smartmontools-devel/Makefile
+++ b/sysutils/smartmontools-devel/Makefile
@@ -25,10 +25,22 @@ USE_RC_SUBR= smartd
MAN5= smartd.conf.5
MAN8= smartd.8 smartctl.8
+OPTIONS= CISS "Support ciss(4) -- requires kernel source tree" off
+
+.include <bsd.port.pre.mk>
+
+.if defined(WITH_CISS)
+. if !exists(/sys/dev/ciss/cissio.h)
+IGNORE= built WITH_CISS requires /sys/dev/ciss/cissio.h
+. endif
+CFLAGS+= -I/sys/dev/ciss -I${FILESDIR}
+EXTRA_PATCHES= ${FILESDIR}/ciss-patch
+.endif
+
post-patch:
@${REINPLACE_CMD} -e 's| install-initdDATA | |' ${WRKSRC}/Makefile.in
post-install:
@${CAT} ${PKGMESSAGE}
-.include <bsd.port.mk>
+.include <bsd.port.post.mk>
diff --git a/sysutils/smartmontools-devel/files/ciss-patch b/sysutils/smartmontools-devel/files/ciss-patch
new file mode 100644
index 000000000000..1c0e627d39fe
--- /dev/null
+++ b/sysutils/smartmontools-devel/files/ciss-patch
@@ -0,0 +1,172 @@
+--- os_freebsd.cpp Sat Sep 16 23:17:53 2006
++++ os_freebsd.cpp Sat Mar 3 05:00:36 2007
+@@ -38,4 +39,5 @@
+ #include "utility.h"
+ #include "os_freebsd.h"
++#include "extern.h"
+
+ static const char *filenameandversion="$Id: os_freebsd.cpp,v 1.51 2006/09/17 03:17:53 dpgilbert Exp $";
+@@ -47,4 +49,7 @@
+ extern int exitstatus;
+
++/* for passing global control variables */
++extern smartmonctrl *con;
++
+ // Private table of open devices: guaranteed zero on startup since
+ // part of static data.
+@@ -86,8 +91,11 @@
+
+ // Like open(). Return positive integer handle, used by functions below only. mode=="ATA" or "SCSI".
+-int deviceopen (const char* dev, char* mode __unused) {
++int deviceopen (const char* dev, char* mode) {
+ struct freebsd_dev_channel *fdchan;
+ int parse_ok, i;
+
++ if (strcasecmp(mode, "CCISS") == 0)
++ return open(dev, O_RDONLY);
++
+ // Search table for a free entry
+ for (i=0; i<FREEBSD_MAXDEV; i++)
+@@ -440,5 +453,6 @@
+
+ // Interface to SCSI devices. See os_linux.c
+-int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
++static int
++do_normal_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
+ {
+ struct freebsd_dev_channel* con = NULL;
+@@ -541,4 +555,21 @@
+ }
+
++#include "ciss_common.c"
++
++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;
++ }
++}
++
+ // Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c
+
+@@ -871,16 +902,17 @@
+ // specific) SCSI device name in FreeBSD can be sd, sr, scd, st, nst,
+ // osst, nosst and sg.
+-static const char * fbsd_dev_prefix = "/dev/";
+-static const char * fbsd_dev_ata_disk_prefix = "ad";
+-static const char * fbsd_dev_scsi_disk_plus = "da";
+-static const char * fbsd_dev_scsi_tape1 = "sa";
+-static const char * fbsd_dev_scsi_tape2 = "nsa";
+-static const char * fbsd_dev_scsi_tape3 = "esa";
+-static const char * fbsd_dev_twe_ctrl = "twe";
+-static const char * fbsd_dev_twa_ctrl = "twa";
++static const char fbsd_dev_prefix[] = "/dev/";
++static const char fbsd_dev_ata_disk_prefix[] = "ad";
++static const char fbsd_dev_scsi_disk_plus[] = "da";
++static const char fbsd_dev_scsi_tape1[] = "sa";
++static const char fbsd_dev_scsi_tape2[] = "nsa";
++static const char fbsd_dev_scsi_tape3[] = "esa";
++static const char fbsd_dev_twe_ctrl[] = "twe";
++static const char fbsd_dev_twa_ctrl[] = "twa";
++static const char fbsd_dev_ciss_ctrl[] = "ciss";
+
+ static int parse_ata_chan_dev(const char * dev_name, struct freebsd_dev_channel *chan) {
+ int len;
+- int dev_prefix_len = strlen(fbsd_dev_prefix);
++ int dev_prefix_len = sizeof fbsd_dev_prefix - 1;
+
+ // if dev_name null, or string length zero
+@@ -898,5 +930,5 @@
+ // form /dev/ad* or ad*
+ if (!strncmp(fbsd_dev_ata_disk_prefix, dev_name,
+- strlen(fbsd_dev_ata_disk_prefix))) {
++ sizeof fbsd_dev_ata_disk_prefix - 1)) {
+ #ifndef IOCATAREQUEST
+ if (chan != NULL) {
+@@ -911,24 +943,24 @@
+ // form /dev/da* or da*
+ if (!strncmp(fbsd_dev_scsi_disk_plus, dev_name,
+- strlen(fbsd_dev_scsi_disk_plus)))
++ sizeof fbsd_dev_scsi_disk_plus - 1))
+ goto handlescsi;
+
+ // form /dev/sa* or sa*
+ if (!strncmp(fbsd_dev_scsi_tape1, dev_name,
+- strlen(fbsd_dev_scsi_tape1)))
++ sizeof fbsd_dev_scsi_tape1 - 1))
+ goto handlescsi;
+
+ // form /dev/nsa* or nsa*
+ if (!strncmp(fbsd_dev_scsi_tape2, dev_name,
+- strlen(fbsd_dev_scsi_tape2)))
++ sizeof fbsd_dev_scsi_tape2 - 1))
+ goto handlescsi;
+
+ // form /dev/esa* or esa*
+ if (!strncmp(fbsd_dev_scsi_tape3, dev_name,
+- strlen(fbsd_dev_scsi_tape3)))
++ sizeof fbsd_dev_scsi_tape3 - 1))
+ goto handlescsi;
+
+ if (!strncmp(fbsd_dev_twa_ctrl,dev_name,
+- strlen(fbsd_dev_twa_ctrl))) {
++ sizeof fbsd_dev_twa_ctrl - 1)) {
+ if (chan != NULL) {
+ if (get_tw_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) {
+@@ -943,5 +975,5 @@
+
+ if (!strncmp(fbsd_dev_twe_ctrl,dev_name,
+- strlen(fbsd_dev_twe_ctrl))) {
++ sizeof fbsd_dev_twe_ctrl - 1)) {
+ if (chan != NULL) {
+ if (get_tw_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) {
+@@ -953,4 +985,13 @@
+ }
+ return CONTROLLER_3WARE_678K_CHAR;
++ }
++ // form /dev/esa* or esa*
++ if (!strncmp(fbsd_dev_ciss_ctrl, dev_name,
++ sizeof fbsd_dev_ciss_ctrl - 1)) {
++ // This is of dubious value, as the desired disk's (unit's) number
++ // still must be specified explicitly with the `-d' option
++ warnx("Use the `-d' option to access drives behind %s. "
++ "See smartctl(8) manual page.", dev_name);
++ return CONTROLLER_CCISS;
+ }
+
+--- smartctl.8.in Wed Dec 20 02:30:43 2006
++++ smartctl.8.in Sat Mar 3 05:22:28 2007
+@@ -303,5 +303,5 @@
+ .B HighPoint RocketRAID controllers are currently ONLY supported under Linux.
+
+-.B cciss controllers are currently ONLY supported under Linux.
++.B cciss controllers are currently ONLY supported under Linux and FreeBSD.
+
+ .TP
+@@ -1257,7 +1257,7 @@
+ .PP
+ .nf
+-.B smartctl \-a \-d cciss,0 /dev/cciss/c0d0
++.B smartctl \-a \-d cciss,0 /dev/ciss0
+ .fi
+-Examine all SMART data for the first SCSI disk connected to a cciss
++Examine all SMART data for the first SCSI disk connected to the first ciss
+ RAID controller card.
+ .PP
+--- smartd.8.in Wed Dec 20 02:30:43 2006
++++ smartd.8.in Sat Mar 3 05:24:51 2007
+@@ -717,5 +717,5 @@
+ with XX in the range from 00 to 15 inclusive.
+
+-.B 3ware and cciss controllers are currently ONLY supported under Linux.
++.B 3ware and cciss controllers are currently ONLY supported under Linux and FreeBSD.
+
+ .I hpt,L/M/N
diff --git a/sysutils/smartmontools-devel/files/ciss_common.c b/sysutils/smartmontools-devel/files/ciss_common.c
new file mode 100644
index 000000000000..80dfaf812cf0
--- /dev/null
+++ b/sysutils/smartmontools-devel/files/ciss_common.c
@@ -0,0 +1,197 @@
+/*
+ * This bits are ripped almost verbatim from os_linux.cpp to allow
+ * FreeBSD, which has the same ciss-ioctls as Linux, to access
+ * individual drives behind ciss(4) controllers.
+ * Authors of smartmontools may wish to make this code shared between
+ * *BSD and Linux, but * currently it remains a duplicate.
+ *
+ * Mikhail T. <mi@aldan.algebra.com>
+ */
+
+/*
+ * This header is not currently installed under /usr/include. Thus
+ * having a kernel source tree is required to compile this file. Use:
+ *
+ * -I/sys/dev/ciss
+ *
+ * to build. Rather unfortunate...
+ */
+#include <cissio.h>
+
+#define SEND_IOCTL_RESP_SENSE_LEN 16 /* ioctl limitation */
+#define LSCSI_DRIVER_SENSE 0x8 /* alternate CHECK CONDITION indication */
+
+static int cciss_io_interface(int device, int target,
+ struct scsi_cmnd_io * iop, int report);
+
+typedef int8_t BYTE; /* some kind of Linuxism? */
+typedef uint32_t DWORD;
+
+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
+
+// 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)))
+ {
+ perror("CCISS ioctl error");
+ }
+ 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
+
+/* 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 */
+ }
+ }
diff --git a/sysutils/smartmontools/Makefile b/sysutils/smartmontools/Makefile
index 189dc559c37e..158c22081338 100644
--- a/sysutils/smartmontools/Makefile
+++ b/sysutils/smartmontools/Makefile
@@ -25,10 +25,22 @@ USE_RC_SUBR= smartd
MAN5= smartd.conf.5
MAN8= smartd.8 smartctl.8
+OPTIONS= CISS "Support ciss(4) -- requires kernel source tree" off
+
+.include <bsd.port.pre.mk>
+
+.if defined(WITH_CISS)
+. if !exists(/sys/dev/ciss/cissio.h)
+IGNORE= built WITH_CISS requires /sys/dev/ciss/cissio.h
+. endif
+CFLAGS+= -I/sys/dev/ciss -I${FILESDIR}
+EXTRA_PATCHES= ${FILESDIR}/ciss-patch
+.endif
+
post-patch:
@${REINPLACE_CMD} -e 's| install-initdDATA | |' ${WRKSRC}/Makefile.in
post-install:
@${CAT} ${PKGMESSAGE}
-.include <bsd.port.mk>
+.include <bsd.port.post.mk>
diff --git a/sysutils/smartmontools/files/ciss-patch b/sysutils/smartmontools/files/ciss-patch
new file mode 100644
index 000000000000..1c0e627d39fe
--- /dev/null
+++ b/sysutils/smartmontools/files/ciss-patch
@@ -0,0 +1,172 @@
+--- os_freebsd.cpp Sat Sep 16 23:17:53 2006
++++ os_freebsd.cpp Sat Mar 3 05:00:36 2007
+@@ -38,4 +39,5 @@
+ #include "utility.h"
+ #include "os_freebsd.h"
++#include "extern.h"
+
+ static const char *filenameandversion="$Id: os_freebsd.cpp,v 1.51 2006/09/17 03:17:53 dpgilbert Exp $";
+@@ -47,4 +49,7 @@
+ extern int exitstatus;
+
++/* for passing global control variables */
++extern smartmonctrl *con;
++
+ // Private table of open devices: guaranteed zero on startup since
+ // part of static data.
+@@ -86,8 +91,11 @@
+
+ // Like open(). Return positive integer handle, used by functions below only. mode=="ATA" or "SCSI".
+-int deviceopen (const char* dev, char* mode __unused) {
++int deviceopen (const char* dev, char* mode) {
+ struct freebsd_dev_channel *fdchan;
+ int parse_ok, i;
+
++ if (strcasecmp(mode, "CCISS") == 0)
++ return open(dev, O_RDONLY);
++
+ // Search table for a free entry
+ for (i=0; i<FREEBSD_MAXDEV; i++)
+@@ -440,5 +453,6 @@
+
+ // Interface to SCSI devices. See os_linux.c
+-int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
++static int
++do_normal_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
+ {
+ struct freebsd_dev_channel* con = NULL;
+@@ -541,4 +555,21 @@
+ }
+
++#include "ciss_common.c"
++
++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;
++ }
++}
++
+ // Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c
+
+@@ -871,16 +902,17 @@
+ // specific) SCSI device name in FreeBSD can be sd, sr, scd, st, nst,
+ // osst, nosst and sg.
+-static const char * fbsd_dev_prefix = "/dev/";
+-static const char * fbsd_dev_ata_disk_prefix = "ad";
+-static const char * fbsd_dev_scsi_disk_plus = "da";
+-static const char * fbsd_dev_scsi_tape1 = "sa";
+-static const char * fbsd_dev_scsi_tape2 = "nsa";
+-static const char * fbsd_dev_scsi_tape3 = "esa";
+-static const char * fbsd_dev_twe_ctrl = "twe";
+-static const char * fbsd_dev_twa_ctrl = "twa";
++static const char fbsd_dev_prefix[] = "/dev/";
++static const char fbsd_dev_ata_disk_prefix[] = "ad";
++static const char fbsd_dev_scsi_disk_plus[] = "da";
++static const char fbsd_dev_scsi_tape1[] = "sa";
++static const char fbsd_dev_scsi_tape2[] = "nsa";
++static const char fbsd_dev_scsi_tape3[] = "esa";
++static const char fbsd_dev_twe_ctrl[] = "twe";
++static const char fbsd_dev_twa_ctrl[] = "twa";
++static const char fbsd_dev_ciss_ctrl[] = "ciss";
+
+ static int parse_ata_chan_dev(const char * dev_name, struct freebsd_dev_channel *chan) {
+ int len;
+- int dev_prefix_len = strlen(fbsd_dev_prefix);
++ int dev_prefix_len = sizeof fbsd_dev_prefix - 1;
+
+ // if dev_name null, or string length zero
+@@ -898,5 +930,5 @@
+ // form /dev/ad* or ad*
+ if (!strncmp(fbsd_dev_ata_disk_prefix, dev_name,
+- strlen(fbsd_dev_ata_disk_prefix))) {
++ sizeof fbsd_dev_ata_disk_prefix - 1)) {
+ #ifndef IOCATAREQUEST
+ if (chan != NULL) {
+@@ -911,24 +943,24 @@
+ // form /dev/da* or da*
+ if (!strncmp(fbsd_dev_scsi_disk_plus, dev_name,
+- strlen(fbsd_dev_scsi_disk_plus)))
++ sizeof fbsd_dev_scsi_disk_plus - 1))
+ goto handlescsi;
+
+ // form /dev/sa* or sa*
+ if (!strncmp(fbsd_dev_scsi_tape1, dev_name,
+- strlen(fbsd_dev_scsi_tape1)))
++ sizeof fbsd_dev_scsi_tape1 - 1))
+ goto handlescsi;
+
+ // form /dev/nsa* or nsa*
+ if (!strncmp(fbsd_dev_scsi_tape2, dev_name,
+- strlen(fbsd_dev_scsi_tape2)))
++ sizeof fbsd_dev_scsi_tape2 - 1))
+ goto handlescsi;
+
+ // form /dev/esa* or esa*
+ if (!strncmp(fbsd_dev_scsi_tape3, dev_name,
+- strlen(fbsd_dev_scsi_tape3)))
++ sizeof fbsd_dev_scsi_tape3 - 1))
+ goto handlescsi;
+
+ if (!strncmp(fbsd_dev_twa_ctrl,dev_name,
+- strlen(fbsd_dev_twa_ctrl))) {
++ sizeof fbsd_dev_twa_ctrl - 1)) {
+ if (chan != NULL) {
+ if (get_tw_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) {
+@@ -943,5 +975,5 @@
+
+ if (!strncmp(fbsd_dev_twe_ctrl,dev_name,
+- strlen(fbsd_dev_twe_ctrl))) {
++ sizeof fbsd_dev_twe_ctrl - 1)) {
+ if (chan != NULL) {
+ if (get_tw_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) {
+@@ -953,4 +985,13 @@
+ }
+ return CONTROLLER_3WARE_678K_CHAR;
++ }
++ // form /dev/esa* or esa*
++ if (!strncmp(fbsd_dev_ciss_ctrl, dev_name,
++ sizeof fbsd_dev_ciss_ctrl - 1)) {
++ // This is of dubious value, as the desired disk's (unit's) number
++ // still must be specified explicitly with the `-d' option
++ warnx("Use the `-d' option to access drives behind %s. "
++ "See smartctl(8) manual page.", dev_name);
++ return CONTROLLER_CCISS;
+ }
+
+--- smartctl.8.in Wed Dec 20 02:30:43 2006
++++ smartctl.8.in Sat Mar 3 05:22:28 2007
+@@ -303,5 +303,5 @@
+ .B HighPoint RocketRAID controllers are currently ONLY supported under Linux.
+
+-.B cciss controllers are currently ONLY supported under Linux.
++.B cciss controllers are currently ONLY supported under Linux and FreeBSD.
+
+ .TP
+@@ -1257,7 +1257,7 @@
+ .PP
+ .nf
+-.B smartctl \-a \-d cciss,0 /dev/cciss/c0d0
++.B smartctl \-a \-d cciss,0 /dev/ciss0
+ .fi
+-Examine all SMART data for the first SCSI disk connected to a cciss
++Examine all SMART data for the first SCSI disk connected to the first ciss
+ RAID controller card.
+ .PP
+--- smartd.8.in Wed Dec 20 02:30:43 2006
++++ smartd.8.in Sat Mar 3 05:24:51 2007
+@@ -717,5 +717,5 @@
+ with XX in the range from 00 to 15 inclusive.
+
+-.B 3ware and cciss controllers are currently ONLY supported under Linux.
++.B 3ware and cciss controllers are currently ONLY supported under Linux and FreeBSD.
+
+ .I hpt,L/M/N
diff --git a/sysutils/smartmontools/files/ciss_common.c b/sysutils/smartmontools/files/ciss_common.c
new file mode 100644
index 000000000000..80dfaf812cf0
--- /dev/null
+++ b/sysutils/smartmontools/files/ciss_common.c
@@ -0,0 +1,197 @@
+/*
+ * This bits are ripped almost verbatim from os_linux.cpp to allow
+ * FreeBSD, which has the same ciss-ioctls as Linux, to access
+ * individual drives behind ciss(4) controllers.
+ * Authors of smartmontools may wish to make this code shared between
+ * *BSD and Linux, but * currently it remains a duplicate.
+ *
+ * Mikhail T. <mi@aldan.algebra.com>
+ */
+
+/*
+ * This header is not currently installed under /usr/include. Thus
+ * having a kernel source tree is required to compile this file. Use:
+ *
+ * -I/sys/dev/ciss
+ *
+ * to build. Rather unfortunate...
+ */
+#include <cissio.h>
+
+#define SEND_IOCTL_RESP_SENSE_LEN 16 /* ioctl limitation */
+#define LSCSI_DRIVER_SENSE 0x8 /* alternate CHECK CONDITION indication */
+
+static int cciss_io_interface(int device, int target,
+ struct scsi_cmnd_io * iop, int report);
+
+typedef int8_t BYTE; /* some kind of Linuxism? */
+typedef uint32_t DWORD;
+
+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
+
+// 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)))
+ {
+ perror("CCISS ioctl error");
+ }
+ 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
+
+/* 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 */
+ }
+ }