- Add optional ciss(4) support, defaults to off

Submitted by:	mi
This commit is contained in:
Pav Lucistnik 2007-03-03 13:05:41 +00:00
parent 16c71ba0be
commit d146de2fad
Notes: svn2git 2021-03-31 03:12:20 +00:00
svn path=/head/; revision=186402
6 changed files with 764 additions and 2 deletions

View file

@ -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>

View file

@ -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

View file

@ -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 */
}
}

View file

@ -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>

View file

@ -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

View file

@ -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 */
}
}