version 1.1.1.2, 2012/10/09 09:36:45
|
version 1.1.1.3, 2013/07/22 01:17:35
|
Line 65
|
Line 65
|
#include <stddef.h> // for offsetof() |
#include <stddef.h> // for offsetof() |
#include <sys/uio.h> |
#include <sys/uio.h> |
#include <sys/types.h> |
#include <sys/types.h> |
|
#include <dirent.h> |
#ifndef makedev // old versions of types.h do not include sysmacros.h |
#ifndef makedev // old versions of types.h do not include sysmacros.h |
#include <sys/sysmacros.h> |
#include <sys/sysmacros.h> |
#endif |
#endif |
Line 82
|
Line 83
|
|
|
#include "dev_interface.h" |
#include "dev_interface.h" |
#include "dev_ata_cmd_set.h" |
#include "dev_ata_cmd_set.h" |
|
#include "dev_areca.h" |
|
|
#ifndef ENOTSUP |
#ifndef ENOTSUP |
#define ENOTSUP ENOSYS |
#define ENOTSUP ENOSYS |
Line 91
|
Line 93
|
|
|
const char * os_linux_cpp_cvsid = "$Id$" |
const char * os_linux_cpp_cvsid = "$Id$" |
OS_LINUX_H_CVSID; |
OS_LINUX_H_CVSID; |
|
extern unsigned char failuretest_permissive; |
|
|
|
|
namespace os_linux { // No need to publish anything, name provided for Doxygen |
namespace os_linux { // No need to publish anything, name provided for Doxygen |
|
|
///////////////////////////////////////////////////////////////////////////// |
///////////////////////////////////////////////////////////////////////////// |
Line 121 class linux_smart_device (protected)
|
Line 123 class linux_smart_device (protected)
|
int get_fd() const |
int get_fd() const |
{ return m_fd; } |
{ return m_fd; } |
|
|
|
void set_fd(int fd) |
|
{ m_fd = fd; } |
|
|
private: |
private: |
int m_fd; ///< filedesc, -1 if not open. |
int m_fd; ///< filedesc, -1 if not open. |
int m_flags; ///< Flags for ::open() |
int m_flags; ///< Flags for ::open() |
int m_retry_flags; ///< Flags to retry ::open(), -1 if no retry |
int m_retry_flags; ///< Flags to retry ::open(), -1 if no retry |
}; |
}; |
|
|
|
|
linux_smart_device::~linux_smart_device() throw() |
linux_smart_device::~linux_smart_device() throw() |
{ |
{ |
if (m_fd >= 0) |
if (m_fd >= 0) |
Line 201 static const char smartctl_examples[] =
|
Line 205 static const char smartctl_examples[] =
|
" on Areca RAID controller)\n" |
" on Areca RAID controller)\n" |
; |
; |
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
///////////////////////////////////////////////////////////////////////////// |
/// Linux ATA support |
/// Linux ATA support |
|
|
Line 242 linux_ata_device::linux_ata_device(smart_interface * i
|
Line 245 linux_ata_device::linux_ata_device(smart_interface * i
|
// 0 if the command succeeded and disk SMART status is "OK" |
// 0 if the command succeeded and disk SMART status is "OK" |
// 1 if the command succeeded and disk SMART status is "FAILING" |
// 1 if the command succeeded and disk SMART status is "FAILING" |
|
|
|
|
#define BUFFER_LENGTH (4+512) |
#define BUFFER_LENGTH (4+512) |
|
|
int linux_ata_device::ata_command_interface(smart_command_set command, int select, char * data) |
int linux_ata_device::ata_command_interface(smart_command_set command, int select, char * data) |
Line 849 linux_scsi_device::linux_scsi_device(smart_interface *
|
Line 851 linux_scsi_device::linux_scsi_device(smart_interface *
|
{ |
{ |
} |
} |
|
|
|
|
bool linux_scsi_device::scsi_pass_through(scsi_cmnd_io * iop) |
bool linux_scsi_device::scsi_pass_through(scsi_cmnd_io * iop) |
{ |
{ |
int status = do_normal_scsi_cmnd_io(get_fd(), iop, scsi_debugmode); |
int status = do_normal_scsi_cmnd_io(get_fd(), iop, scsi_debugmode); |
Line 875 class linux_megaraid_device (public)
|
Line 876 class linux_megaraid_device (public)
|
|
|
virtual bool open(); |
virtual bool open(); |
virtual bool close(); |
virtual bool close(); |
| |
virtual bool scsi_pass_through(scsi_cmnd_io *iop); |
virtual bool scsi_pass_through(scsi_cmnd_io *iop); |
|
|
private: |
private: |
Line 885 class linux_megaraid_device (public)
|
Line 886 class linux_megaraid_device (public)
|
int m_fd; |
int m_fd; |
|
|
bool (linux_megaraid_device::*pt_cmd)(int cdblen, void *cdb, int dataLen, void *data, |
bool (linux_megaraid_device::*pt_cmd)(int cdblen, void *cdb, int dataLen, void *data, |
int senseLen, void *sense, int report); | int senseLen, void *sense, int report, int direction); |
bool megasas_cmd(int cdbLen, void *cdb, int dataLen, void *data, |
bool megasas_cmd(int cdbLen, void *cdb, int dataLen, void *data, |
int senseLen, void *sense, int report); | int senseLen, void *sense, int report, int direction); |
bool megadev_cmd(int cdbLen, void *cdb, int dataLen, void *data, |
bool megadev_cmd(int cdbLen, void *cdb, int dataLen, void *data, |
int senseLen, void *sense, int report); | int senseLen, void *sense, int report, int direction); |
}; |
}; |
|
|
linux_megaraid_device::linux_megaraid_device(smart_interface *intf, |
linux_megaraid_device::linux_megaraid_device(smart_interface *intf, |
Line 900 linux_megaraid_device::linux_megaraid_device(smart_int
|
Line 901 linux_megaraid_device::linux_megaraid_device(smart_int
|
m_fd(-1), pt_cmd(0) |
m_fd(-1), pt_cmd(0) |
{ |
{ |
set_info().info_name = strprintf("%s [megaraid_disk_%02d]", dev_name, m_disknum); |
set_info().info_name = strprintf("%s [megaraid_disk_%02d]", dev_name, m_disknum); |
|
set_info().dev_type = strprintf("megaraid,%d", tgt); |
} |
} |
|
|
linux_megaraid_device::~linux_megaraid_device() throw() |
linux_megaraid_device::~linux_megaraid_device() throw() |
Line 939 smart_device * linux_megaraid_device::autodetect_open(
|
Line 941 smart_device * linux_megaraid_device::autodetect_open(
|
|
|
// Use INQUIRY to detect type |
// Use INQUIRY to detect type |
{ |
{ |
// SAT or USB ? | // SAT? |
ata_device * newdev = smi()->autodetect_sat_device(this, req_buff, len); |
ata_device * newdev = smi()->autodetect_sat_device(this, req_buff, len); |
if (newdev) { | if (newdev) // NOTE: 'this' is now owned by '*newdev' |
// NOTE: 'this' is now owned by '*newdev' | |
newdev->close(); | |
newdev->set_err(ENOSYS, "SATA device detected,\n" | |
"MegaRAID SAT layer is reportedly buggy, use '-d sat+megaraid,N' to try anyhow"); | |
return newdev; |
return newdev; |
} |
|
} |
} |
|
|
// Nothing special found |
// Nothing special found |
return this; |
return this; |
} |
} |
|
|
|
|
bool linux_megaraid_device::open() |
bool linux_megaraid_device::open() |
{ |
{ |
char line[128]; |
char line[128]; |
int mjr, n1; | int mjr; |
FILE *fp; | |
int report = scsi_debugmode; |
int report = scsi_debugmode; |
|
|
if (!linux_smart_device::open()) | if(sscanf(get_dev_name(),"/dev/bus/%d", &m_hba) == 0) { |
return false; | if (!linux_smart_device::open()) |
| return false; |
/* Get device HBA */ | /* Get device HBA */ |
struct sg_scsi_id sgid; | struct sg_scsi_id sgid; |
if (ioctl(get_fd(), SG_GET_SCSI_ID, &sgid) == 0) { | if (ioctl(get_fd(), SG_GET_SCSI_ID, &sgid) == 0) { |
m_hba = sgid.host_no; | m_hba = sgid.host_no; |
} | } |
else if (ioctl(get_fd(), SCSI_IOCTL_GET_BUS_NUMBER, &m_hba) != 0) { | else if (ioctl(get_fd(), SCSI_IOCTL_GET_BUS_NUMBER, &m_hba) != 0) { |
int err = errno; | int err = errno; |
| linux_smart_device::close(); |
| return set_err(err, "can't get bus number"); |
| } // we dont need this device anymore |
linux_smart_device::close(); |
linux_smart_device::close(); |
return set_err(err, "can't get bus number"); |
|
} |
} |
|
|
/* Perform mknod of device ioctl node */ |
/* Perform mknod of device ioctl node */ |
fp = fopen("/proc/devices", "r"); | FILE * fp = fopen("/proc/devices", "r"); |
while (fgets(line, sizeof(line), fp) != NULL) { |
while (fgets(line, sizeof(line), fp) != NULL) { |
n1=0; | int n1 = 0; |
if (sscanf(line, "%d megaraid_sas_ioctl%n", &mjr, &n1) == 1 && n1 == 22) { | if (sscanf(line, "%d megaraid_sas_ioctl%n", &mjr, &n1) == 1 && n1 == 22) { |
n1=mknod("/dev/megaraid_sas_ioctl_node", S_IFCHR, makedev(mjr, 0)); | n1=mknod("/dev/megaraid_sas_ioctl_node", S_IFCHR, makedev(mjr, 0)); |
if(report > 0) | if(report > 0) |
pout("Creating /dev/megaraid_sas_ioctl_node = %d\n", n1 >= 0 ? 0 : errno); | pout("Creating /dev/megaraid_sas_ioctl_node = %d\n", n1 >= 0 ? 0 : errno); |
if (n1 >= 0 || errno == EEXIST) | if (n1 >= 0 || errno == EEXIST) |
break; | break; |
} | } |
else if (sscanf(line, "%d megadev%n", &mjr, &n1) == 1 && n1 == 11) { | else if (sscanf(line, "%d megadev%n", &mjr, &n1) == 1 && n1 == 11) { |
n1=mknod("/dev/megadev0", S_IFCHR, makedev(mjr, 0)); | n1=mknod("/dev/megadev0", S_IFCHR, makedev(mjr, 0)); |
if(report > 0) | if(report > 0) |
pout("Creating /dev/megadev0 = %d\n", n1 >= 0 ? 0 : errno); | pout("Creating /dev/megadev0 = %d\n", n1 >= 0 ? 0 : errno); |
if (n1 >= 0 || errno == EEXIST) | if (n1 >= 0 || errno == EEXIST) |
break; | break; |
} | } |
} |
} |
fclose(fp); |
fclose(fp); |
|
|
Line 1009 bool linux_megaraid_device::open()
|
Line 1005 bool linux_megaraid_device::open()
|
linux_smart_device::close(); |
linux_smart_device::close(); |
return set_err(err, "cannot open /dev/megaraid_sas_ioctl_node or /dev/megadev0"); |
return set_err(err, "cannot open /dev/megaraid_sas_ioctl_node or /dev/megadev0"); |
} |
} |
| set_fd(m_fd); |
return true; |
return true; |
} |
} |
|
|
Line 1018 bool linux_megaraid_device::close()
|
Line 1014 bool linux_megaraid_device::close()
|
if (m_fd >= 0) |
if (m_fd >= 0) |
::close(m_fd); |
::close(m_fd); |
m_fd = -1; m_hba = 0; pt_cmd = 0; |
m_fd = -1; m_hba = 0; pt_cmd = 0; |
return linux_smart_device::close(); | set_fd(m_fd); |
| return true; |
} |
} |
|
|
bool linux_megaraid_device::scsi_pass_through(scsi_cmnd_io *iop) |
bool linux_megaraid_device::scsi_pass_through(scsi_cmnd_io *iop) |
Line 1061 bool linux_megaraid_device::scsi_pass_through(scsi_cmn
|
Line 1058 bool linux_megaraid_device::scsi_pass_through(scsi_cmn
|
return set_err(ENOSYS, "ATA return descriptor not supported by controller firmware"); |
return set_err(ENOSYS, "ATA return descriptor not supported by controller firmware"); |
} |
} |
// SMART WRITE LOG SECTOR causing media errors |
// SMART WRITE LOG SECTOR causing media errors |
if ((iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16 && iop->cmnd[14] == ATA_SMART_CMD | if ((iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16 // SAT16 WRITE LOG |
&& iop->cmnd[3]==0 && iop->cmnd[4] == ATA_SMART_WRITE_LOG_SECTOR) || | && iop->cmnd[14] == ATA_SMART_CMD && iop->cmnd[3]==0 && iop->cmnd[4] == ATA_SMART_WRITE_LOG_SECTOR) || |
(iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 && iop->cmnd[9] == ATA_SMART_CMD && | (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 // SAT12 WRITE LOG |
iop->cmnd[3] == ATA_SMART_WRITE_LOG_SECTOR)) | && iop->cmnd[9] == ATA_SMART_CMD && iop->cmnd[3] == ATA_SMART_WRITE_LOG_SECTOR)) |
return set_err(ENOSYS, "SMART WRITE LOG SECTOR command is not supported by controller firmware"); | { |
| if(!failuretest_permissive) |
| return set_err(ENOSYS, "SMART WRITE LOG SECTOR may cause problems, try with -T permissive to force"); |
| } |
if (pt_cmd == NULL) |
if (pt_cmd == NULL) |
return false; |
return false; |
return (this->*pt_cmd)(iop->cmnd_len, iop->cmnd, | return (this->*pt_cmd)(iop->cmnd_len, iop->cmnd, |
iop->dxfer_len, iop->dxferp, |
iop->dxfer_len, iop->dxferp, |
iop->max_sense_len, iop->sensep, report); | iop->max_sense_len, iop->sensep, report, iop->dxfer_dir); |
} |
} |
|
|
/* Issue passthrough scsi command to PERC5/6 controllers */ |
/* Issue passthrough scsi command to PERC5/6 controllers */ |
bool linux_megaraid_device::megasas_cmd(int cdbLen, void *cdb, |
bool linux_megaraid_device::megasas_cmd(int cdbLen, void *cdb, |
int dataLen, void *data, |
int dataLen, void *data, |
int /*senseLen*/, void * /*sense*/, int /*report*/) | int /*senseLen*/, void * /*sense*/, int /*report*/, int dxfer_dir) |
{ |
{ |
struct megasas_pthru_frame *pthru; |
struct megasas_pthru_frame *pthru; |
struct megasas_iocpacket uio; |
struct megasas_iocpacket uio; |
Line 1092 bool linux_megaraid_device::megasas_cmd(int cdbLen, vo
|
Line 1091 bool linux_megaraid_device::megasas_cmd(int cdbLen, vo
|
pthru->lun = 0; |
pthru->lun = 0; |
pthru->cdb_len = cdbLen; |
pthru->cdb_len = cdbLen; |
pthru->timeout = 0; |
pthru->timeout = 0; |
pthru->flags = MFI_FRAME_DIR_READ; | switch (dxfer_dir) { |
| case DXFER_NONE: |
| pthru->flags = MFI_FRAME_DIR_NONE; |
| break; |
| case DXFER_FROM_DEVICE: |
| pthru->flags = MFI_FRAME_DIR_READ; |
| break; |
| case DXFER_TO_DEVICE: |
| pthru->flags = MFI_FRAME_DIR_WRITE; |
| break; |
| default: |
| pout("megasas_cmd: bad dxfer_dir\n"); |
| return set_err(EINVAL, "megasas_cmd: bad dxfer_dir\n"); |
| } |
| |
if (dataLen > 0) { |
if (dataLen > 0) { |
pthru->sge_count = 1; |
pthru->sge_count = 1; |
pthru->data_xfer_len = dataLen; |
pthru->data_xfer_len = dataLen; |
Line 1126 bool linux_megaraid_device::megasas_cmd(int cdbLen, vo
|
Line 1139 bool linux_megaraid_device::megasas_cmd(int cdbLen, vo
|
/* Issue passthrough scsi commands to PERC2/3/4 controllers */ |
/* Issue passthrough scsi commands to PERC2/3/4 controllers */ |
bool linux_megaraid_device::megadev_cmd(int cdbLen, void *cdb, |
bool linux_megaraid_device::megadev_cmd(int cdbLen, void *cdb, |
int dataLen, void *data, |
int dataLen, void *data, |
int /*senseLen*/, void * /*sense*/, int /*report*/) | int /*senseLen*/, void * /*sense*/, int /*report*/, int /* dir */) |
{ |
{ |
struct uioctl_t uio; |
struct uioctl_t uio; |
int rc; |
int rc; |
Line 1261 static int setup_3ware_nodes(const char *nodename, con
|
Line 1274 static int setup_3ware_nodes(const char *nodename, con
|
int selinux_enforced = security_getenforce(); |
int selinux_enforced = security_getenforce(); |
#endif |
#endif |
|
|
|
|
/* First try to open up /proc/devices */ |
/* First try to open up /proc/devices */ |
if (!(file = fopen("/proc/devices", "r"))) { |
if (!(file = fopen("/proc/devices", "r"))) { |
pout("Error opening /proc/devices to check/create 3ware device nodes\n"); |
pout("Error opening /proc/devices to check/create 3ware device nodes\n"); |
Line 1301 static int setup_3ware_nodes(const char *nodename, con
|
Line 1313 static int setup_3ware_nodes(const char *nodename, con
|
#endif |
#endif |
/* Now check if nodes are correct */ |
/* Now check if nodes are correct */ |
for (index=0; index<16; index++) { |
for (index=0; index<16; index++) { |
sprintf(nodestring, "/dev/%s%d", nodename, index); | snprintf(nodestring, sizeof(nodestring), "/dev/%s%d", nodename, index); |
#ifdef WITH_SELINUX |
#ifdef WITH_SELINUX |
/* Get context of the node and set it as the default */ |
/* Get context of the node and set it as the default */ |
if (selinux_enabled) { |
if (selinux_enabled) { |
Line 1434 bool linux_escalade_device::open()
|
Line 1446 bool linux_escalade_device::open()
|
// 0 if the command succeeded and disk SMART status is "OK" |
// 0 if the command succeeded and disk SMART status is "OK" |
// 1 if the command succeeded and disk SMART status is "FAILING" |
// 1 if the command succeeded and disk SMART status is "FAILING" |
|
|
|
|
/* 512 is the max payload size: increase if needed */ |
/* 512 is the max payload size: increase if needed */ |
#define BUFFER_LEN_678K ( sizeof(TW_Ioctl) ) // 1044 unpacked, 1041 packed |
#define BUFFER_LEN_678K ( sizeof(TW_Ioctl) ) // 1044 unpacked, 1041 packed |
#define BUFFER_LEN_678K_CHAR ( sizeof(TW_New_Ioctl)+512-1 ) // 1539 unpacked, 1536 packed |
#define BUFFER_LEN_678K_CHAR ( sizeof(TW_New_Ioctl)+512-1 ) // 1539 unpacked, 1536 packed |
Line 1644 bool linux_escalade_device::ata_pass_through(const ata
|
Line 1655 bool linux_escalade_device::ata_pass_through(const ata
|
return true; |
return true; |
} |
} |
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
///////////////////////////////////////////////////////////////////////////// |
/// Areca RAID support |
/// Areca RAID support |
|
|
class linux_areca_device | /////////////////////////////////////////////////////////////////// |
: public /*implements*/ ata_device, | // SATA(ATA) device behind Areca RAID Controller |
| class linux_areca_ata_device |
| : public /*implements*/ areca_ata_device, |
public /*extends*/ linux_smart_device |
public /*extends*/ linux_smart_device |
{ |
{ |
public: |
public: |
linux_areca_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); | linux_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); |
| virtual smart_device * autodetect_open(); |
protected: | virtual bool arcmsr_lock(); |
virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); | virtual bool arcmsr_unlock(); |
| virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop); |
private: | |
int m_disknum; ///< Disk number. | |
int m_encnum; ///< Enclosure number. | |
}; |
}; |
|
|
| /////////////////////////////////////////////////////////////////// |
// PURPOSE | // SAS(SCSI) device behind Areca RAID Controller |
// This is an interface routine meant to isolate the OS dependent | class linux_areca_scsi_device |
// parts of the code, and to provide a debugging interface. Each | : public /*implements*/ areca_scsi_device, |
// different port and OS needs to provide it's own interface. This | public /*extends*/ linux_smart_device |
// is the linux interface to the Areca "arcmsr" driver. It allows ATA | |
// commands to be passed through the SCSI driver. | |
// DETAILED DESCRIPTION OF ARGUMENTS | |
// fd: is the file descriptor provided by open() | |
// disknum is the disk number (0 to 15) in the RAID array | |
// command: defines the different operations. | |
// select: additional input data if needed (which log, which type of | |
// self-test). | |
// data: location to write output data, if needed (512 bytes). | |
// Note: not all commands use all arguments. | |
// RETURN VALUES | |
// -1 if the command failed | |
// 0 if the command succeeded, | |
// STATUS_CHECK routine: | |
// -1 if the command failed | |
// 0 if the command succeeded and disk SMART status is "OK" | |
// 1 if the command succeeded and disk SMART status is "FAILING" | |
| |
| |
/*DeviceType*/ | |
#define ARECA_SATA_RAID 0x90000000 | |
/*FunctionCode*/ | |
#define FUNCTION_READ_RQBUFFER 0x0801 | |
#define FUNCTION_WRITE_WQBUFFER 0x0802 | |
#define FUNCTION_CLEAR_RQBUFFER 0x0803 | |
#define FUNCTION_CLEAR_WQBUFFER 0x0804 | |
| |
/* ARECA IO CONTROL CODE*/ | |
#define ARCMSR_IOCTL_READ_RQBUFFER (ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER) | |
#define ARCMSR_IOCTL_WRITE_WQBUFFER (ARECA_SATA_RAID | FUNCTION_WRITE_WQBUFFER) | |
#define ARCMSR_IOCTL_CLEAR_RQBUFFER (ARECA_SATA_RAID | FUNCTION_CLEAR_RQBUFFER) | |
#define ARCMSR_IOCTL_CLEAR_WQBUFFER (ARECA_SATA_RAID | FUNCTION_CLEAR_WQBUFFER) | |
#define ARECA_SIG_STR "ARCMSR" | |
| |
// The SRB_IO_CONTROL & SRB_BUFFER structures are used to communicate(to/from) to areca driver | |
typedef struct _SRB_IO_CONTROL | |
{ |
{ |
unsigned int HeaderLength; | public: |
unsigned char Signature[8]; | linux_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); |
unsigned int Timeout; | virtual smart_device * autodetect_open(); |
unsigned int ControlCode; | virtual bool arcmsr_lock(); |
unsigned int ReturnCode; | virtual bool arcmsr_unlock(); |
unsigned int Length; | virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop); |
} sSRB_IO_CONTROL; | }; |
|
|
typedef struct _SRB_BUFFER |
|
{ |
|
sSRB_IO_CONTROL srbioctl; |
|
unsigned char ioctldatabuffer[1032]; // the buffer to put the command data to/from firmware |
|
} sSRB_BUFFER; |
|
|
|
// Looks in /proc/scsi to suggest correct areca devices |
// Looks in /proc/scsi to suggest correct areca devices |
// If hint not NULL, return device path guess | static int find_areca_in_proc() |
static int find_areca_in_proc(char *hint) | |
{ |
{ |
const char* proc_format_string="host\tchan\tid\tlun\ttype\topens\tqdepth\tbusy\tonline\n"; |
const char* proc_format_string="host\tchan\tid\tlun\ttype\topens\tqdepth\tbusy\tonline\n"; |
|
|
Line 1760 static int find_areca_in_proc(char *hint)
|
Line 1726 static int find_areca_in_proc(char *hint)
|
dev++; |
dev++; |
if (id == 16 && type == 3) { |
if (id == 16 && type == 3) { |
// devices with id=16 and type=3 might be Areca controllers |
// devices with id=16 and type=3 might be Areca controllers |
if (!found && hint) { |
|
sprintf(hint, "/dev/sg%d", dev); |
|
} |
|
pout("Device /dev/sg%d appears to be an Areca controller.\n", dev); |
pout("Device /dev/sg%d appears to be an Areca controller.\n", dev); |
found++; |
found++; |
} |
} |
Line 1771 static int find_areca_in_proc(char *hint)
|
Line 1734 static int find_areca_in_proc(char *hint)
|
return 0; |
return 0; |
} |
} |
|
|
|
// Areca RAID Controller(SATA Disk) |
|
linux_areca_ata_device::linux_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) |
|
: smart_device(intf, dev_name, "areca", "areca"), |
|
linux_smart_device(O_RDWR | O_EXCL | O_NONBLOCK) |
|
{ |
|
set_disknum(disknum); |
|
set_encnum(encnum); |
|
set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); |
|
} |
|
|
#if 0 // For debugging areca code | smart_device * linux_areca_ata_device::autodetect_open() |
| |
static void dumpdata(unsigned char *block, int len) | |
{ |
{ |
int ln = (len / 16) + 1; // total line# | int is_ata = 1; |
unsigned char c; | |
int pos = 0; | |
|
|
printf(" Address = %p, Length = (0x%x)%d\n", block, len, len); | // autodetect device type |
printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F ASCII \n"); | is_ata = arcmsr_get_dev_type(); |
printf("=====================================================================\n"); | if(is_ata < 0) |
| { |
| set_err(EIO); |
| return this; |
| } |
|
|
for ( int l = 0; l < ln && len; l++ ) | if(is_ata == 1) |
{ | { |
// printf the line# and the HEX data | // SATA device |
// if a line data length < 16 then append the space to the tail of line to reach 16 chars | return this; |
printf("%02X | ", l); | } |
for ( pos = 0; pos < 16 && len; pos++, len-- ) | |
{ | |
c = block[l*16+pos]; | |
printf("%02X ", c); | |
} | |
|
|
if ( pos < 16 ) | // SAS device |
{ | smart_device_auto_ptr newdev(new linux_areca_scsi_device(smi(), get_dev_name(), get_disknum(), get_encnum())); |
for ( int loop = pos; loop < 16; loop++ ) | close(); |
{ | delete this; |
printf(" "); | newdev->open(); // TODO: Can possibly pass open fd |
} | |
} | |
|
|
// print ASCII char | return newdev.release(); |
for ( int loop = 0; loop < pos; loop++ ) | |
{ | |
c = block[l*16+loop]; | |
if ( c >= 0x20 && c <= 0x7F ) | |
{ | |
printf("%c", c); | |
} | |
else | |
{ | |
printf("."); | |
} | |
} | |
printf("\n"); | |
} | |
printf("=====================================================================\n"); | |
} |
} |
|
|
#endif | int linux_areca_ata_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop) |
| |
static int arcmsr_command_handler(int fd, unsigned long arcmsr_cmd, unsigned char *data, int data_len, void *ext_data /* reserved for further use */) | |
{ |
{ |
ARGUSED(ext_data); | int ioctlreturn = 0; |
|
|
int ioctlreturn = 0; | if(!is_open()) { |
sSRB_BUFFER sBuf; | if(!open()){ |
struct scsi_cmnd_io io_hdr; | find_areca_in_proc(); |
int dir = DXFER_TO_DEVICE; | } |
| } |
|
|
UINT8 cdb[10]; | ioctlreturn = do_normal_scsi_cmnd_io(get_fd(), iop, scsi_debugmode); |
UINT8 sense[32]; | if ( ioctlreturn || iop->scsi_status ) |
| { |
| // errors found |
| return -1; |
| } |
|
|
unsigned char *areca_return_packet; | return ioctlreturn; |
int total = 0; | } |
int expected = -1; | |
unsigned char return_buff[2048]; | |
unsigned char *ptr = &return_buff[0]; | |
memset(return_buff, 0, sizeof(return_buff)); | |
|
|
memset((unsigned char *)&sBuf, 0, sizeof(sBuf)); | bool linux_areca_ata_device::arcmsr_lock() |
memset(&io_hdr, 0, sizeof(io_hdr)); | { |
memset(cdb, 0, sizeof(cdb)); | return true; |
memset(sense, 0, sizeof(sense)); | } |
|
|
| bool linux_areca_ata_device::arcmsr_unlock() |
sBuf.srbioctl.HeaderLength = sizeof(sSRB_IO_CONTROL); | { |
memcpy(sBuf.srbioctl.Signature, ARECA_SIG_STR, strlen(ARECA_SIG_STR)); | return true; |
sBuf.srbioctl.Timeout = 10000; | |
sBuf.srbioctl.ControlCode = ARCMSR_IOCTL_READ_RQBUFFER; | |
| |
switch ( arcmsr_cmd ) | |
{ | |
// command for writing data to driver | |
case ARCMSR_IOCTL_WRITE_WQBUFFER: | |
if ( data && data_len ) | |
{ | |
sBuf.srbioctl.Length = data_len; | |
memcpy((unsigned char *)sBuf.ioctldatabuffer, (unsigned char *)data, data_len); | |
} | |
// commands for clearing related buffer of driver | |
case ARCMSR_IOCTL_CLEAR_RQBUFFER: | |
case ARCMSR_IOCTL_CLEAR_WQBUFFER: | |
cdb[0] = 0x3B; //SCSI_WRITE_BUF command; | |
break; | |
// command for reading data from driver | |
case ARCMSR_IOCTL_READ_RQBUFFER: | |
cdb[0] = 0x3C; //SCSI_READ_BUF command; | |
dir = DXFER_FROM_DEVICE; | |
break; | |
default: | |
// unknown arcmsr commands | |
return -1; | |
} | |
| |
cdb[1] = 0x01; | |
cdb[2] = 0xf0; | |
// | |
// cdb[5][6][7][8] areca defined command code( to/from driver ) | |
// | |
cdb[5] = (char)( arcmsr_cmd >> 24); | |
cdb[6] = (char)( arcmsr_cmd >> 16); | |
cdb[7] = (char)( arcmsr_cmd >> 8); | |
cdb[8] = (char)( arcmsr_cmd & 0x0F ); | |
| |
io_hdr.dxfer_dir = dir; | |
io_hdr.dxfer_len = sizeof(sBuf); | |
io_hdr.dxferp = (unsigned char *)&sBuf; | |
io_hdr.cmnd = cdb; | |
io_hdr.cmnd_len = sizeof(cdb); | |
io_hdr.sensep = sense; | |
io_hdr.max_sense_len = sizeof(sense); | |
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; | |
| |
while ( 1 ) | |
{ | |
ioctlreturn = do_normal_scsi_cmnd_io(fd, &io_hdr, 0); | |
if ( ioctlreturn || io_hdr.scsi_status ) | |
{ | |
// errors found | |
break; | |
} | |
| |
if ( arcmsr_cmd != ARCMSR_IOCTL_READ_RQBUFFER ) | |
{ | |
// if succeeded, just returns the length of outgoing data | |
return data_len; | |
} | |
| |
if ( sBuf.srbioctl.Length ) | |
{ | |
//dumpdata(&sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length); | |
memcpy(ptr, &sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length); | |
ptr += sBuf.srbioctl.Length; | |
total += sBuf.srbioctl.Length; | |
// the returned bytes enough to compute payload length ? | |
if ( expected < 0 && total >= 5 ) | |
{ | |
areca_return_packet = (unsigned char *)&return_buff[0]; | |
if ( areca_return_packet[0] == 0x5E && | |
areca_return_packet[1] == 0x01 && | |
areca_return_packet[2] == 0x61 ) | |
{ | |
// valid header, let's compute the returned payload length, | |
// we expected the total length is | |
// payload + 3 bytes header + 2 bytes length + 1 byte checksum | |
expected = areca_return_packet[4] * 256 + areca_return_packet[3] + 6; | |
} | |
} | |
| |
if ( total >= 7 && total >= expected ) | |
{ | |
//printf("total bytes received = %d, expected length = %d\n", total, expected); | |
| |
// ------ Okay! we received enough -------- | |
break; | |
} | |
} | |
} | |
| |
// Deal with the different error cases | |
if ( ioctlreturn ) | |
{ | |
pout("do_scsi_cmnd_io with write buffer failed code = %x\n", ioctlreturn); | |
return -2; | |
} | |
| |
| |
if ( io_hdr.scsi_status ) | |
{ | |
pout("io_hdr.scsi_status with write buffer failed code = %x\n", io_hdr.scsi_status); | |
return -3; | |
} | |
| |
| |
if ( data ) | |
{ | |
memcpy(data, return_buff, total); | |
} | |
| |
return total; | |
} |
} |
|
|
| // Areca RAID Controller(SAS Device) |
linux_areca_device::linux_areca_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) | linux_areca_scsi_device::linux_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) |
: smart_device(intf, dev_name, "areca", "areca"), |
: smart_device(intf, dev_name, "areca", "areca"), |
linux_smart_device(O_RDWR | O_EXCL | O_NONBLOCK), | linux_smart_device(O_RDWR | O_EXCL | O_NONBLOCK) |
m_disknum(disknum), | |
m_encnum(encnum) | |
{ |
{ |
|
set_disknum(disknum); |
|
set_encnum(encnum); |
set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); |
set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); |
} |
} |
|
|
// Areca RAID Controller | smart_device * linux_areca_scsi_device::autodetect_open() |
// int linux_areca_device::ata_command_interface(smart_command_set command, int select, char * data) | |
bool linux_areca_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) | |
{ |
{ |
if (!ata_cmd_is_ok(in, | return this; |
true, // data_out_support | } |
false, // TODO: multi_sector_support | |
true) // ata_48bit_support | |
) | |
return false; | |
|
|
// ATA input registers | int linux_areca_scsi_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop) |
typedef struct _ATA_INPUT_REGISTERS | { |
{ | int ioctlreturn = 0; |
unsigned char features; | |
unsigned char sector_count; | |
unsigned char sector_number; | |
unsigned char cylinder_low; | |
unsigned char cylinder_high; | |
unsigned char device_head; | |
unsigned char command; | |
unsigned char reserved[8]; | |
unsigned char data[512]; // [in/out] buffer for outgoing/incoming data | |
} sATA_INPUT_REGISTERS; | |
|
|
// ATA output registers | if(!is_open()) { |
// Note: The output registers is re-sorted for areca internal use only | if(!open()){ |
typedef struct _ATA_OUTPUT_REGISTERS | find_areca_in_proc(); |
{ | } |
unsigned char error; | } |
unsigned char status; | |
unsigned char sector_count; | |
unsigned char sector_number; | |
unsigned char cylinder_low; | |
unsigned char cylinder_high; | |
}sATA_OUTPUT_REGISTERS; | |
|
|
// Areca packet format for outgoing: | ioctlreturn = do_normal_scsi_cmnd_io(get_fd(), iop, scsi_debugmode); |
// B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61 | if ( ioctlreturn || iop->scsi_status ) |
// B[3~4] : 2 bytes command length + variant data length, little endian | { |
// B[5] : 1 bytes areca defined command code, ATA passthrough command code is 0x1c | // errors found |
// B[6~last-1] : variant bytes payload data | return -1; |
// B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1]) | } |
// | |
// | |
// header 3 bytes length 2 bytes cmd 1 byte payload data x bytes cs 1 byte | |
// +--------------------------------------------------------------------------------+ | |
// + 0x5E 0x01 0x61 | 0x00 0x00 | 0x1c | .................... | 0x00 | | |
// +--------------------------------------------------------------------------------+ | |
// | |
|
|
//Areca packet format for incoming: | return ioctlreturn; |
// B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61 | } |
// B[3~4] : 2 bytes payload length, little endian | |
// B[5~last-1] : variant bytes returned payload data | |
// B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1]) | |
// | |
// | |
// header 3 bytes length 2 bytes payload data x bytes cs 1 byte | |
// +-------------------------------------------------------------------+ | |
// + 0x5E 0x01 0x61 | 0x00 0x00 | .................... | 0x00 | | |
// +-------------------------------------------------------------------+ | |
unsigned char areca_packet[640]; | |
int areca_packet_len = sizeof(areca_packet); | |
unsigned char cs = 0; | |
|
|
sATA_INPUT_REGISTERS *ata_cmd; | bool linux_areca_scsi_device::arcmsr_lock() |
| { |
| return true; |
| } |
|
|
// For debugging | bool linux_areca_scsi_device::arcmsr_unlock() |
#if 0 | { |
memset(sInq, 0, sizeof(sInq)); | return true; |
scsiStdInquiry(fd, (unsigned char *)sInq, (int)sizeof(sInq)); | |
dumpdata((unsigned char *)sInq, sizeof(sInq)); | |
#endif | |
memset(areca_packet, 0, areca_packet_len); | |
| |
// ----- BEGIN TO SETUP HEADERS ------- | |
areca_packet[0] = 0x5E; | |
areca_packet[1] = 0x01; | |
areca_packet[2] = 0x61; | |
areca_packet[3] = (unsigned char)((areca_packet_len - 6) & 0xff); | |
areca_packet[4] = (unsigned char)(((areca_packet_len - 6) >> 8) & 0xff); | |
areca_packet[5] = 0x1c; // areca defined code for ATA passthrough command | |
| |
// ----- BEGIN TO SETUP PAYLOAD DATA ----- | |
memcpy(&areca_packet[7], "SmrT", 4); // areca defined password | |
ata_cmd = (sATA_INPUT_REGISTERS *)&areca_packet[12]; | |
| |
// Set registers | |
{ | |
const ata_in_regs_48bit & r = in.in_regs; | |
ata_cmd->features = r.features_16; | |
ata_cmd->sector_count = r.sector_count_16; | |
ata_cmd->sector_number = r.lba_low_16; | |
ata_cmd->cylinder_low = r.lba_mid_16; | |
ata_cmd->cylinder_high = r.lba_high_16; | |
ata_cmd->device_head = r.device; | |
ata_cmd->command = r.command; | |
} | |
bool readdata = false; | |
if (in.direction == ata_cmd_in::data_in) { | |
readdata = true; | |
// the command will read data | |
areca_packet[6] = 0x13; | |
} | |
else if ( in.direction == ata_cmd_in::no_data ) | |
{ | |
// the commands will return no data | |
areca_packet[6] = 0x15; | |
} | |
else if (in.direction == ata_cmd_in::data_out) | |
{ | |
// the commands will write data | |
memcpy(ata_cmd->data, in.buffer, in.size); | |
areca_packet[6] = 0x14; | |
} | |
else { | |
// COMMAND NOT SUPPORTED VIA ARECA IOCTL INTERFACE | |
return set_err(ENOTSUP, "DATA OUT not supported for this Areca controller type"); | |
} | |
| |
areca_packet[11] = m_disknum - 1; // disk# | |
areca_packet[19] = m_encnum - 1; // enc# | |
| |
// ----- BEGIN TO SETUP CHECKSUM ----- | |
for ( int loop = 3; loop < areca_packet_len - 1; loop++ ) | |
{ | |
cs += areca_packet[loop]; | |
} | |
areca_packet[areca_packet_len-1] = cs; | |
| |
// ----- BEGIN TO SEND TO ARECA DRIVER ------ | |
int expected = 0; | |
unsigned char return_buff[2048]; | |
memset(return_buff, 0, sizeof(return_buff)); | |
| |
expected = arcmsr_command_handler(get_fd(), ARCMSR_IOCTL_CLEAR_RQBUFFER, NULL, 0, NULL); | |
if (expected==-3) { | |
find_areca_in_proc(NULL); | |
return set_err(EIO); | |
} | |
| |
expected = arcmsr_command_handler(get_fd(), ARCMSR_IOCTL_CLEAR_WQBUFFER, NULL, 0, NULL); | |
expected = arcmsr_command_handler(get_fd(), ARCMSR_IOCTL_WRITE_WQBUFFER, areca_packet, areca_packet_len, NULL); | |
if ( expected > 0 ) | |
{ | |
expected = arcmsr_command_handler(get_fd(), ARCMSR_IOCTL_READ_RQBUFFER, return_buff, sizeof(return_buff), NULL); | |
} | |
if ( expected < 0 ) | |
{ | |
return -1; | |
} | |
| |
// ----- VERIFY THE CHECKSUM ----- | |
cs = 0; | |
for ( int loop = 3; loop < expected - 1; loop++ ) | |
{ | |
cs += return_buff[loop]; | |
} | |
| |
if ( return_buff[expected - 1] != cs ) | |
{ | |
return set_err(EIO); | |
} | |
| |
sATA_OUTPUT_REGISTERS *ata_out = (sATA_OUTPUT_REGISTERS *)&return_buff[5] ; | |
if ( ata_out->status ) | |
{ | |
if ( in.in_regs.command == ATA_IDENTIFY_DEVICE | |
&& !nonempty((unsigned char *)in.buffer, in.size)) | |
{ | |
return set_err(ENODEV, "No drive on port %d", m_disknum); | |
} | |
} | |
| |
// returns with data | |
if (readdata) | |
{ | |
memcpy(in.buffer, &return_buff[7], in.size); | |
} | |
| |
// Return register values | |
{ | |
ata_out_regs_48bit & r = out.out_regs; | |
r.error = ata_out->error; | |
r.sector_count_16 = ata_out->sector_count; | |
r.lba_low_16 = ata_out->sector_number; | |
r.lba_mid_16 = ata_out->cylinder_low; | |
r.lba_high_16 = ata_out->cylinder_high; | |
r.status = ata_out->status; | |
} | |
return true; | |
} |
} |
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
///////////////////////////////////////////////////////////////////////////// |
/// Marvell support |
/// Marvell support |
|
|
Line 2317 int linux_marvell_device::ata_command_interface(smart_
|
Line 1993 int linux_marvell_device::ata_command_interface(smart_
|
return 0; |
return 0; |
} |
} |
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
///////////////////////////////////////////////////////////////////////////// |
/// Highpoint RAID support |
/// Highpoint RAID support |
|
|
Line 2550 int linux_highpoint_device::ata_command_interface(smar
|
Line 2225 int linux_highpoint_device::ata_command_interface(smar
|
return 0; |
return 0; |
} |
} |
|
|
|
|
#if 0 // TODO: Migrate from 'smart_command_set' to 'ata_in_regs' OR remove the function |
#if 0 // TODO: Migrate from 'smart_command_set' to 'ata_in_regs' OR remove the function |
// Utility function for printing warnings |
// Utility function for printing warnings |
void printwarning(smart_command_set command){ |
void printwarning(smart_command_set command){ |
Line 2582 void printwarning(smart_command_set command){
|
Line 2256 void printwarning(smart_command_set command){
|
} |
} |
#endif |
#endif |
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
///////////////////////////////////////////////////////////////////////////// |
/// SCSI open with autodetection support |
/// SCSI open with autodetection support |
|
|
Line 2640 smart_device * linux_scsi_device::autodetect_open()
|
Line 2313 smart_device * linux_scsi_device::autodetect_open()
|
} |
} |
|
|
// DELL? |
// DELL? |
if (!memcmp(req_buff + 8, "DELL PERC", 12) || !memcmp(req_buff + 8, "MegaRAID", 8)) { | if (!memcmp(req_buff + 8, "DELL PERC", 12) || !memcmp(req_buff + 8, "MegaRAID", 8) |
| || !memcmp(req_buff + 16, "PERC H700", 9) || !memcmp(req_buff + 8, "LSI\0",4) |
| ) { |
close(); |
close(); |
set_err(EINVAL, "DELL or MegaRaid controller, please try adding '-d megaraid,N'"); |
set_err(EINVAL, "DELL or MegaRaid controller, please try adding '-d megaraid,N'"); |
return this; |
return this; |
Line 2676 smart_device * linux_scsi_device::autodetect_open()
|
Line 2351 smart_device * linux_scsi_device::autodetect_open()
|
return this; |
return this; |
} |
} |
|
|
|
|
////////////////////////////////////////////////////////////////////// |
////////////////////////////////////////////////////////////////////// |
// USB bridge ID detection |
// USB bridge ID detection |
|
|
Line 2730 static bool get_usb_id(const char * name, unsigned sho
|
Line 2404 static bool get_usb_id(const char * name, unsigned sho
|
return true; |
return true; |
} |
} |
|
|
|
|
////////////////////////////////////////////////////////////////////// |
////////////////////////////////////////////////////////////////////// |
/// Linux interface |
/// Linux interface |
|
|
Line 2759 class linux_smart_interface (protected)
|
Line 2432 class linux_smart_interface (protected)
|
private: |
private: |
bool get_dev_list(smart_device_list & devlist, const char * pattern, |
bool get_dev_list(smart_device_list & devlist, const char * pattern, |
bool scan_ata, bool scan_scsi, const char * req_type, bool autodetect); |
bool scan_ata, bool scan_scsi, const char * req_type, bool autodetect); |
| bool get_dev_megasas(smart_device_list & devlist); |
smart_device * missing_option(const char * opt); |
smart_device * missing_option(const char * opt); |
|
int megasas_dcmd_cmd(int bus_no, uint32_t opcode, void *buf, |
|
size_t bufsize, uint8_t *mbox, size_t mboxlen, uint8_t *statusp); |
|
int megasas_pd_add_list(int bus_no, smart_device_list & devlist); |
}; |
}; |
|
|
std::string linux_smart_interface::get_os_version_str() |
std::string linux_smart_interface::get_os_version_str() |
Line 2779 std::string linux_smart_interface::get_app_examples(co
|
Line 2455 std::string linux_smart_interface::get_app_examples(co
|
return ""; |
return ""; |
} |
} |
|
|
|
|
// we are going to take advantage of the fact that Linux's devfs will only |
// we are going to take advantage of the fact that Linux's devfs will only |
// have device entries for devices that exist. So if we get the equivalent of |
// have device entries for devices that exist. So if we get the equivalent of |
// ls /dev/hd[a-t], we have all the ATA devices on the system |
// ls /dev/hd[a-t], we have all the ATA devices on the system |
Line 2876 bool linux_smart_interface::get_dev_list(smart_device_
|
Line 2551 bool linux_smart_interface::get_dev_list(smart_device_
|
|
|
// free memory |
// free memory |
globfree(&globbuf); |
globfree(&globbuf); |
|
return true; |
|
} |
|
|
|
// getting devices from LSI SAS MegaRaid, if available |
|
bool linux_smart_interface::get_dev_megasas(smart_device_list & devlist) |
|
{ |
|
/* Scanning of disks on MegaRaid device */ |
|
/* Perform mknod of device ioctl node */ |
|
int mjr, n1; |
|
char line[128]; |
|
bool scan_megasas = false; |
|
FILE * fp = fopen("/proc/devices", "r"); |
|
while (fgets(line, sizeof(line), fp) != NULL) { |
|
n1=0; |
|
if (sscanf(line, "%d megaraid_sas_ioctl%n", &mjr, &n1) == 1 && n1 == 22) { |
|
scan_megasas = true; |
|
n1=mknod("/dev/megaraid_sas_ioctl_node", S_IFCHR, makedev(mjr, 0)); |
|
if(scsi_debugmode > 0) |
|
pout("Creating /dev/megaraid_sas_ioctl_node = %d\n", n1 >= 0 ? 0 : errno); |
|
if (n1 >= 0 || errno == EEXIST) |
|
break; |
|
} |
|
} |
|
fclose(fp); |
|
|
|
if(!scan_megasas) |
|
return false; |
|
|
|
// getting bus numbers with megasas devices |
|
struct dirent *ep; |
|
unsigned int host_no = 0; |
|
char sysfsdir[256]; |
|
|
|
/* we are using sysfs to get list of all scsi hosts */ |
|
DIR * dp = opendir ("/sys/class/scsi_host/"); |
|
if (dp != NULL) |
|
{ |
|
while ((ep = readdir (dp)) != NULL) { |
|
if (!sscanf(ep->d_name, "host%d", &host_no)) |
|
continue; |
|
/* proc_name should be megaraid_sas */ |
|
snprintf(sysfsdir, sizeof(sysfsdir) - 1, |
|
"/sys/class/scsi_host/host%d/proc_name", host_no); |
|
if((fp = fopen(sysfsdir, "r")) == NULL) |
|
continue; |
|
if(fgets(line, sizeof(line), fp) != NULL && !strncmp(line,"megaraid_sas",12)) { |
|
megasas_pd_add_list(host_no, devlist); |
|
} |
|
fclose(fp); |
|
} |
|
(void) closedir (dp); |
|
} else { /* sysfs not mounted ? */ |
|
for(unsigned i = 0; i <=16; i++) // trying to add devices on first 16 buses |
|
megasas_pd_add_list(i, devlist); |
|
} |
return true; |
return true; |
} |
} |
|
|
Line 2904 bool linux_smart_interface::scan_smart_devices(smart_d
|
Line 2633 bool linux_smart_interface::scan_smart_devices(smart_d
|
get_dev_list(devlist, "/dev/sd[a-z]", false, true, type, autodetect); |
get_dev_list(devlist, "/dev/sd[a-z]", false, true, type, autodetect); |
// Support up to 104 devices |
// Support up to 104 devices |
get_dev_list(devlist, "/dev/sd[a-c][a-z]", false, true, type, autodetect); |
get_dev_list(devlist, "/dev/sd[a-c][a-z]", false, true, type, autodetect); |
|
// get device list from the megaraid device |
|
get_dev_megasas(devlist); |
} |
} |
|
|
// if we found traditional links, we are done |
// if we found traditional links, we are done |
Line 2931 smart_device * linux_smart_interface::missing_option(c
|
Line 2662 smart_device * linux_smart_interface::missing_option(c
|
return 0; |
return 0; |
} |
} |
|
|
|
int |
|
linux_smart_interface::megasas_dcmd_cmd(int bus_no, uint32_t opcode, void *buf, |
|
size_t bufsize, uint8_t *mbox, size_t mboxlen, uint8_t *statusp) |
|
{ |
|
struct megasas_iocpacket ioc; |
|
|
|
if ((mbox != NULL && (mboxlen == 0 || mboxlen > MFI_MBOX_SIZE)) || |
|
(mbox == NULL && mboxlen != 0)) |
|
{ |
|
errno = EINVAL; |
|
return (-1); |
|
} |
|
|
|
bzero(&ioc, sizeof(ioc)); |
|
struct megasas_dcmd_frame * dcmd = &ioc.frame.dcmd; |
|
ioc.host_no = bus_no; |
|
if (mbox) |
|
bcopy(mbox, dcmd->mbox.w, mboxlen); |
|
dcmd->cmd = MFI_CMD_DCMD; |
|
dcmd->timeout = 0; |
|
dcmd->flags = 0; |
|
dcmd->data_xfer_len = bufsize; |
|
dcmd->opcode = opcode; |
|
|
|
if (bufsize > 0) { |
|
dcmd->sge_count = 1; |
|
dcmd->data_xfer_len = bufsize; |
|
dcmd->sgl.sge32[0].phys_addr = (intptr_t)buf; |
|
dcmd->sgl.sge32[0].length = (uint32_t)bufsize; |
|
ioc.sge_count = 1; |
|
ioc.sgl_off = offsetof(struct megasas_dcmd_frame, sgl); |
|
ioc.sgl[0].iov_base = buf; |
|
ioc.sgl[0].iov_len = bufsize; |
|
} |
|
|
|
int fd; |
|
if ((fd = ::open("/dev/megaraid_sas_ioctl_node", O_RDWR)) <= 0) { |
|
return (errno); |
|
} |
|
|
|
int r = ioctl(fd, MEGASAS_IOC_FIRMWARE, &ioc); |
|
if (r < 0) { |
|
return (r); |
|
} |
|
|
|
if (statusp != NULL) |
|
*statusp = dcmd->cmd_status; |
|
else if (dcmd->cmd_status != MFI_STAT_OK) { |
|
fprintf(stderr, "command %x returned error status %x\n", |
|
opcode, dcmd->cmd_status); |
|
errno = EIO; |
|
return (-1); |
|
} |
|
return (0); |
|
} |
|
|
|
int |
|
linux_smart_interface::megasas_pd_add_list(int bus_no, smart_device_list & devlist) |
|
{ |
|
/* |
|
* Keep fetching the list in a loop until we have a large enough |
|
* buffer to hold the entire list. |
|
*/ |
|
megasas_pd_list * list = 0; |
|
for (unsigned list_size = 1024; ; ) { |
|
list = (megasas_pd_list *)realloc(list, list_size); |
|
if (!list) |
|
throw std::bad_alloc(); |
|
bzero(list, list_size); |
|
if (megasas_dcmd_cmd(bus_no, MFI_DCMD_PD_GET_LIST, list, list_size, NULL, 0, |
|
NULL) < 0) |
|
{ |
|
free(list); |
|
return (-1); |
|
} |
|
if (list->size <= list_size) |
|
break; |
|
list_size = list->size; |
|
} |
|
|
|
// adding all SCSI devices |
|
for (unsigned i = 0; i < list->count; i++) { |
|
if(list->addr[i].scsi_dev_type) |
|
continue; /* non disk device found */ |
|
char line[128]; |
|
snprintf(line, sizeof(line) - 1, "/dev/bus/%d", bus_no); |
|
smart_device * dev = new linux_megaraid_device(this, line, 0, list->addr[i].device_id); |
|
devlist.push_back(dev); |
|
} |
|
free(list); |
|
return (0); |
|
} |
|
|
// Return kernel release as integer ("2.6.31" -> 206031) |
// Return kernel release as integer ("2.6.31" -> 206031) |
static unsigned get_kernel_release() |
static unsigned get_kernel_release() |
{ |
{ |
Line 3068 smart_device * linux_smart_interface::get_custom_smart
|
Line 2892 smart_device * linux_smart_interface::get_custom_smart
|
set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum); |
set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum); |
return 0; |
return 0; |
} |
} |
return new linux_areca_device(this, name, disknum, encnum); | return new linux_areca_ata_device(this, name, disknum, encnum); |
} |
} |
|
|
// Highpoint ? |
// Highpoint ? |
Line 3128 std::string linux_smart_interface::get_valid_custom_de
|
Line 2952 std::string linux_smart_interface::get_valid_custom_de
|
} |
} |
|
|
} // namespace |
} // namespace |
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
///////////////////////////////////////////////////////////////////////////// |
/// Initialize platform interface and register with smi() |
/// Initialize platform interface and register with smi() |