/*
* os_win32.cpp
*
- * Home page of code is: http://smartmontools.sourceforge.net
+ * Home page of code is: http://www.smartmontools.org
*
- * Copyright (C) 2004-13 Christian Franke <smartmontools-support@lists.sourceforge.net>
- * Copyright (C) 2012 Hank Wu <hank@areca.com.tw>
+ * Copyright (C) 2004-15 Christian Franke
+ *
+ * Original AACRaid code:
+ * Copyright (C) 2015 Nidhi Malhotra <nidhi.malhotra@pmcs.com>
+ *
+ * Original Areca code:
+ * Copyright (C) 2012 Hank Wu <hank@areca.com.tw>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#endif
#ifndef _WIN32
-// csmisas.h requires _WIN32 but w32api-headers no longer define it on Cygwin
+// csmisas.h and aacraid.h require _WIN32 but w32api-headers no longer define it on Cygwin
+// (aacraid.h also checks for _WIN64 which is also set on Cygwin x64)
#define _WIN32
#endif
// CSMI support
#include "csmisas.h"
+// aacraid support
+#include "aacraid.h"
+
// Silence -Wunused-local-typedefs warning from g++ >= 4.8
#if __GNUC__ >= 4
#define ATTR_UNUSED __attribute__((unused))
#define SELECT_WIN_32_64(x32, x64) (x64)
#endif
-const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 3830 2013-07-18 20:59:53Z chrfranke $";
+// Cygwin does no longer provide strn?icmp() compatibility macros
+// MSVCRT does not provide strn?casecmp()
+#if defined(__CYGWIN__) && !defined(stricmp)
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+#endif
+
+const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 4156 2015-10-18 12:20:40Z samm2 $";
/////////////////////////////////////////////////////////////////////////////
// Windows I/O-controls, some declarations are missing in the include files
ASSERT_SIZEOF(CSMI_SAS_PHY_INFO_BUFFER, 2080);
ASSERT_SIZEOF(CSMI_SAS_STP_PASSTHRU_BUFFER, 168);
+// aacraid struct
+
+ASSERT_SIZEOF(SCSI_REQUEST_BLOCK, SELECT_WIN_32_64(64, 88));
+
} // extern "C"
/////////////////////////////////////////////////////////////////////////////
: virtual public /*extends*/ smart_device
{
public:
- /// Get phy info
- bool get_phy_info(CSMI_SAS_PHY_INFO & phy_info);
-
- /// Check physical drive existence
- bool check_phy(const CSMI_SAS_PHY_INFO & phy_info, unsigned phy_no);
+ /// Get bitmask of used ports
+ unsigned get_ports_used();
protected:
csmi_device()
: smart_device(never_called)
{ memset(&m_phy_ent, 0, sizeof(m_phy_ent)); }
+ /// Get phy info
+ bool get_phy_info(CSMI_SAS_PHY_INFO & phy_info);
+
/// Select physical drive
- bool select_phy(unsigned phy_no);
+ bool select_port(int port);
/// Get info for selected physical drive
const CSMI_SAS_PHY_ENTITY & get_phy_ent() const
private:
HANDLE m_fh; ///< Controller device handle
- unsigned m_phy_no; ///< Physical drive number
+ int m_port; ///< Port number
};
ata_smart_values m_smart_buf;
};
+/////////////////////////////////////////////////////////////////////////////
+//// PMC aacraid Support
+
+class win_aacraid_device
+:public /*implements*/ scsi_device,
+public /*extends*/ win_smart_device
+{
+public:
+ win_aacraid_device(smart_interface *intf, const char *dev_name,unsigned int ctrnum, unsigned int target, unsigned int lun);
+
+ virtual ~win_aacraid_device() throw();
+
+ virtual bool open();
+
+ virtual bool scsi_pass_through(struct scsi_cmnd_io *iop);
+
+private:
+ //Device Host number
+ int m_ctrnum;
+
+ //Channel(Lun) of the device
+ int m_lun;
+
+ //Id of the device
+ int m_target;
+};
+
+
/////////////////////////////////////////////////////////////////////////////
/// Areca RAID support
const int vlen = sizeof(vstr)-sizeof(SMARTMONTOOLS_BUILD_HOST);
assert(vptr == vstr+strlen(vstr) && vptr+vlen+1 == vstr+sizeof(vstr));
- OSVERSIONINFOEXA vi; memset(&vi, 0, sizeof(vi));
+ // Starting with Windows 8.1, GetVersionEx() does no longer report the
+ // actual OS version, see:
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
+
+ // RtlGetVersion() is not affected
+ LONG /*NTSTATUS*/ (WINAPI /*NTAPI*/ * RtlGetVersion_p)(LPOSVERSIONINFOEXW) =
+ (LONG (WINAPI *)(LPOSVERSIONINFOEXW))
+ GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlGetVersion");
+
+ OSVERSIONINFOEXW vi; memset(&vi, 0, sizeof(vi));
vi.dwOSVersionInfoSize = sizeof(vi);
- if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
- memset(&vi, 0, sizeof(vi));
- vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
- if (!GetVersionExA((OSVERSIONINFOA *)&vi))
+ if (!RtlGetVersion_p || RtlGetVersion_p(&vi)) {
+ if (!GetVersionExW((OSVERSIONINFOW *)&vi))
return vstr;
}
const char * w = 0;
- if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
-
- if (vi.dwMajorVersion > 6 || (vi.dwMajorVersion == 6 && vi.dwMinorVersion >= 2)) {
- // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the
- // actual OS version, see:
- // http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
-
- ULONGLONG major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
- for (unsigned major = vi.dwMajorVersion; major <= 9; major++) {
- OSVERSIONINFOEXA vi2; memset(&vi2, 0, sizeof(vi2));
- vi2.dwOSVersionInfoSize = sizeof(vi2); vi2.dwMajorVersion = major;
- if (!VerifyVersionInfo(&vi2, VER_MAJORVERSION, major_equal))
- continue;
- if (vi.dwMajorVersion < major) {
- vi.dwMajorVersion = major; vi.dwMinorVersion = 0;
- }
-
- ULONGLONG minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);
- for (unsigned minor = vi.dwMinorVersion; minor <= 9; minor++) {
- memset(&vi2, 0, sizeof(vi2)); vi2.dwOSVersionInfoSize = sizeof(vi2);
- vi2.dwMinorVersion = minor;
- if (!VerifyVersionInfo(&vi2, VER_MINORVERSION, minor_equal))
- continue;
- vi.dwMinorVersion = minor;
- break;
- }
-
- break;
- }
- }
-
- if (vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) {
- bool ws = (vi.wProductType <= VER_NT_WORKSTATION);
- switch (vi.dwMajorVersion << 4 | vi.dwMinorVersion) {
- case 0x50: w = "2000"; break;
- case 0x51: w = "xp"; break;
- case 0x52: w = (!GetSystemMetrics(89/*SM_SERVERR2*/)
- ? "2003" : "2003r2"); break;
- case 0x60: w = (ws ? "vista" : "2008" ); break;
- case 0x61: w = (ws ? "win7" : "2008r2"); break;
- case 0x62: w = (ws ? "win8" : "2012" ); break;
- case 0x63: w = (ws ? "win8.1": "2012r2"); break;
- }
+ if ( vi.dwPlatformId == VER_PLATFORM_WIN32_NT
+ && vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) {
+ bool ws = (vi.wProductType <= VER_NT_WORKSTATION);
+ switch (vi.dwMajorVersion << 4 | vi.dwMinorVersion) {
+ case 0x50: w = "2000"; break;
+ case 0x51: w = "xp"; break;
+ case 0x52: w = (!GetSystemMetrics(89/*SM_SERVERR2*/)
+ ? "2003" : "2003r2"); break;
+ case 0x60: w = (ws ? "vista" : "2008" ); break;
+ case 0x61: w = (ws ? "win7" : "2008r2"); break;
+ case 0x62: w = (ws ? "win8" : "2012" ); break;
+ case 0x63: w = (ws ? "win8.1": "2012r2"); break;
+ case 0x64: w = (ws ? "w10tp" : "w10tps"); break; // 6.4 = Win 10 Technical Preview
+ case 0xa0: w = (ws ? "win10" : "w10srv"); break; // 10.0 = Win 10 Final
}
}
// Return value for device detection functions
-enum win_dev_type { DEV_UNKNOWN = 0, DEV_ATA, DEV_SCSI, DEV_USB };
+enum win_dev_type { DEV_UNKNOWN = 0, DEV_ATA, DEV_SCSI, DEV_SAT, DEV_USB };
static win_dev_type get_phy_drive_type(int drive);
static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex);
static win_dev_type get_log_drive_type(int drive);
-static bool get_usb_id(int drive, unsigned short & vendor_id,
+static bool get_usb_id(int phydrive, int logdrive,
+ unsigned short & vendor_id,
unsigned short & product_id);
static const char * ata_get_def_options(void);
return phydrive;
}
-static win_dev_type get_dev_type(const char * name, int & phydrive)
+static win_dev_type get_dev_type(const char * name, int & phydrive, int & logdrive)
{
- phydrive = -1;
+ phydrive = logdrive = -1;
+
name = skipdev(name);
if (!strncmp(name, "st", 2))
return DEV_SCSI;
if (!strncmp(name, "tape", 4))
return DEV_SCSI;
- int logdrive = drive_letter(name);
+ logdrive = drive_letter(name);
if (logdrive >= 0) {
win_dev_type type = get_log_drive_type(logdrive);
return (type != DEV_UNKNOWN ? type : DEV_SCSI);
return get_phy_drive_type(phydrive);
}
- phydrive = -1;
if (sscanf(name, "pd%d", &phydrive) == 1 && phydrive >= 0)
return get_phy_drive_type(phydrive);
+
return DEV_UNKNOWN;
}
}
else
set_err(EINVAL, "Option -d areca,N/E requires device name /dev/arcmsrX");
+ return 0;
+ }
+
+ // aacraid?
+ unsigned ctrnum, lun, target;
+ n1 = -1;
+
+ if ( sscanf(type, "aacraid,%u,%u,%u%n", &ctrnum, &lun, &target, &n1) >= 3
+ && n1 == (int)strlen(type)) {
+#define aacraid_MAX_CTLR_NUM 16
+ if (ctrnum >= aacraid_MAX_CTLR_NUM) {
+ set_err(EINVAL, "aacraid: invalid host number %u", ctrnum);
+ return 0;
+ }
+
+ /*
+ 1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[AACRAID_MAX_CTLR_NUM]:" and
+ 2. map ARCX into "\\\\.\\scsiX"
+ */
+ memset(devpath, 0, sizeof(devpath));
+ unsigned ctlrindex = 0;
+ for (int portNum = 0; portNum < aacraid_MAX_CTLR_NUM; portNum++){
+ char subKey[63];
+ snprintf(subKey, sizeof(subKey), "HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port %d", portNum);
+ HKEY hScsiKey = 0;
+ long regStatus = RegOpenKeyExA(HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, &hScsiKey);
+ if (regStatus == ERROR_SUCCESS){
+ char driverName[20];
+ DWORD driverNameSize = sizeof(driverName);
+ DWORD regType = 0;
+ regStatus = RegQueryValueExA(hScsiKey, "Driver", NULL, ®Type, (LPBYTE) driverName, &driverNameSize);
+ if (regStatus == ERROR_SUCCESS){
+ if (regType == REG_SZ){
+ if (stricmp(driverName, "arcsas") == 0){
+ if(ctrnum == ctlrindex){
+ snprintf(devpath, sizeof(devpath), "\\\\.\\Scsi%d:", portNum);
+ return get_sat_device("sat,auto",
+ new win_aacraid_device(this, devpath, ctrnum, target, lun));
+ }
+ ctlrindex++;
+ }
+ }
+ }
+ RegCloseKey(hScsiKey);
+ }
+ }
+
+ set_err(EINVAL, "aacraid: host %u not found", ctrnum);
+ return 0;
}
return 0;
std::string win_smart_interface::get_valid_custom_dev_types_str()
{
- return "areca,N[/E]";
+ return "aacraid,H,L,ID, areca,N[/E]";
}
if (str_starts_with(testname, "csmi"))
return new win_csmi_device(this, name, "");
- int phydrive = -1;
- win_dev_type type = get_dev_type(name, phydrive);
+ int phydrive = -1, logdrive = -1;
+ win_dev_type type = get_dev_type(name, phydrive, logdrive);
if (type == DEV_ATA)
return new win_ata_device(this, name, "");
+
if (type == DEV_SCSI)
return new win_scsi_device(this, name, "");
+ if (type == DEV_SAT)
+ return get_sat_device("sat", new win_scsi_device(this, name, ""));
+
if (type == DEV_USB) {
// Get USB bridge ID
unsigned short vendor_id = 0, product_id = 0;
- if (!(phydrive >= 0 && get_usb_id(phydrive, vendor_id, product_id))) {
+ if (!get_usb_id(phydrive, logdrive, vendor_id, product_id)) {
set_err(EINVAL, "Unable to read USB device ID");
return 0;
}
}
// Set valid types
- bool ata, scsi, usb, csmi;
+ bool ata, scsi, sat, usb, csmi;
if (!type) {
- ata = scsi = usb = csmi = true;
+ ata = scsi = usb = sat = csmi = true;
}
else {
- ata = scsi = usb = csmi = false;
+ ata = scsi = usb = sat = csmi = false;
if (!strcmp(type, "ata"))
ata = true;
else if (!strcmp(type, "scsi"))
scsi = true;
+ else if (!strcmp(type, "sat"))
+ sat = true;
else if (!strcmp(type, "usb"))
usb = true;
else if (!strcmp(type, "csmi"))
csmi = true;
else {
- set_err(EINVAL, "Invalid type '%s', valid arguments are: ata[,pd], scsi[,pd], usb[,pd], csmi, pd", type);
+ set_err(EINVAL,
+ "Invalid type '%s', valid arguments are: ata[,pd], scsi[,pd], sat[,pd], usb[,pd], csmi, pd",
+ type);
return false;
}
}
char name[20];
- if (ata || scsi || usb) {
+ if (ata || scsi || sat || usb) {
// Scan up to 128 drives and 2 3ware controllers
const int max_raid = 2;
bool raid_seen[max_raid] = {false, false};
raid_seen[vers_ex.wControllerId] = true;
// Add physical drives
int len = strlen(name);
- for (int pi = 0; pi < 32; pi++) {
+ for (unsigned int pi = 0; pi < 32; pi++) {
if (vers_ex.dwDeviceMapEx & (1L << pi)) {
snprintf(name+len, sizeof(name)-1-len, ",%u", pi);
devlist.push_back( new win_ata_device(this, name, "ata") );
devlist.push_back( new win_scsi_device(this, name, "scsi") );
break;
+ case DEV_SAT:
+ // STORAGE_QUERY_PROPERTY returned VendorId "ATA "
+ if (!sat)
+ continue;
+ devlist.push_back( get_sat_device("sat", new win_scsi_device(this, name, "")) );
+ break;
+
case DEV_USB:
// STORAGE_QUERY_PROPERTY returned USB
if (!usb)
// TODO: Use common function for this and autodetect_smart_device()
// Get USB bridge ID
unsigned short vendor_id = 0, product_id = 0;
- if (!get_usb_id(i, vendor_id, product_id))
+ if (!get_usb_id(i, -1, vendor_id, product_id))
continue;
// Get type name for this ID
const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id);
win_csmi_device test_dev(this, name, "");
if (!test_dev.open_scsi())
continue;
- CSMI_SAS_PHY_INFO phy_info;
- if (!test_dev.get_phy_info(phy_info))
+
+ unsigned ports_used = test_dev.get_ports_used();
+ if (!ports_used)
continue;
- for (int pi = 0; pi < phy_info.bNumberOfPhys; pi++) {
- if (!test_dev.check_phy(phy_info, pi))
+ for (int pi = 0; pi < 32; pi++) {
+ if (!(ports_used & (1 << pi)))
continue;
snprintf(name, sizeof(name)-1, "/dev/csmi%d,%d", i, pi);
devlist.push_back( new win_csmi_device(this, name, "ata") );
/////////////////////////////////////////////////////////////////////////////
+// Return true if ATA drive behind a SAT layer
+static bool is_sat(const STORAGE_DEVICE_DESCRIPTOR_DATA * data)
+{
+ if (!data->desc.VendorIdOffset)
+ return false;
+ if (strcmp(data->raw + data->desc.VendorIdOffset, "ATA "))
+ return false;
+ return true;
+}
+
// Return true if Intel ICHxR RAID volume
static bool is_intel_raid_volume(const STORAGE_DEVICE_DESCRIPTOR_DATA * data)
{
switch ((int)data.desc.BusType) {
case BusTypeAta:
case 0x0b: // BusTypeSata
+ // Certain Intel AHCI drivers (C600+/C220+) have broken
+ // IOCTL_ATA_PASS_THROUGH support and a working SAT layer
+ if (is_sat(&data))
+ return DEV_SAT;
+
if (ata_version_ex)
memset(ata_version_ex, 0, sizeof(*ata_version_ex));
return DEV_ATA;
case BusTypeScsi:
case BusTypeRAID:
+ if (is_sat(&data))
+ return DEV_SAT;
+
// Intel ICHxR RAID volume: reports SMART_GET_VERSION but does not support SMART_*
if (is_intel_raid_volume(&data))
return DEV_SCSI;
// LSI/3ware RAID volume: supports SMART_*
if (admin && smart_get_version(hdevice, ata_version_ex) >= 0)
return DEV_ATA;
+
return DEV_SCSI;
case 0x09: // BusTypeiScsi
case 0x0a: // BusTypeSas
+ if (is_sat(&data))
+ return DEV_SAT;
+
return DEV_SCSI;
case BusTypeUsb:
/////////////////////////////////////////////////////////////////////////////
// USB ID detection using WMI
-// Get USB ID for a physical drive number
-static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & product_id)
+// Get USB ID for a physical or logical drive number
+static bool get_usb_id(int phydrive, int logdrive,
+ unsigned short & vendor_id,
+ unsigned short & product_id)
{
bool debug = (scsi_debugmode > 1);
}
// Get device name
+ std::string name;
+
wbem_object wo;
- if (!ws.query1(wo, "SELECT Model FROM Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive))
+ if (0 <= logdrive && logdrive <= 'Z'-'A') {
+ // Drive letter -> Partition info
+ if (!ws.query1(wo, "ASSOCIATORS OF {Win32_LogicalDisk.DeviceID=\"%c:\"} WHERE ResultClass = Win32_DiskPartition",
+ 'A'+logdrive))
+ return false;
+
+ std::string partid = wo.get_str("DeviceID");
+ if (debug)
+ pout("%c: --> \"%s\" -->\n", 'A'+logdrive, partid.c_str());
+
+ // Partition ID -> Physical drive info
+ if (!ws.query1(wo, "ASSOCIATORS OF {Win32_DiskPartition.DeviceID=\"%s\"} WHERE ResultClass = Win32_DiskDrive",
+ partid.c_str()))
+ return false;
+
+ name = wo.get_str("Model");
+ if (debug)
+ pout("%s --> \"%s\":\n", wo.get_str("DeviceID").c_str(), name.c_str());
+ }
+
+ else if (phydrive >= 0) {
+ // Physical drive number -> Physical drive info
+ if (!ws.query1(wo, "SELECT Model FROM Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", phydrive))
+ return false;
+
+ name = wo.get_str("Model");
+ if (debug)
+ pout("\\.\\\\PHYSICALDRIVE%d --> \"%s\":\n", phydrive, name.c_str());
+ }
+ else
return false;
- std::string name = wo.get_str("Model");
- if (debug)
- pout("PhysicalDrive%d, \"%s\":\n", drive, name.c_str());
// Get USB_CONTROLLER -> DEVICE associations
wbem_enumerator we;
prev_usb_ant = ant;
if (debug)
pout(" +-> \"%s\" [0x%04x:0x%04x]\n", devid.c_str(), prev_usb_venid, prev_usb_proid);
- continue;
}
- else if (str_starts_with(devid, "USBSTOR\\\\")) {
- // USBSTOR device found
+ else if (str_starts_with(devid, "USBSTOR\\\\") || str_starts_with(devid, "SCSI\\\\")) {
+ // USBSTORage or SCSI device found
if (debug)
pout(" +--> \"%s\"\n", devid.c_str());
close();
return set_err(ENOSYS);
}
- devmap = 0x0f;
}
m_smartver_state = 1;
break;
case 'f':
if (in.in_regs.command == ATA_IDENTIFY_DEVICE) {
- rc = get_identify_from_device_property(get_fh(), (ata_identify_device *)data);
+ ata_identify_device * id = reinterpret_cast<ata_identify_device *>(data);
+ rc = get_identify_from_device_property(get_fh(), id);
if (rc == 0 && m_phydrive >= 0)
- get_serial_from_wmi(m_phydrive, (ata_identify_device *)data);
+ get_serial_from_wmi(m_phydrive, id);
id_is_cached = true;
}
else if (in.in_regs.command == ATA_SMART_CMD) switch (in.in_regs.features) {
return false;
phy_info = phy_info_buf.Information;
- if (phy_info.bNumberOfPhys > sizeof(phy_info.Phy)/sizeof(phy_info.Phy[0]))
+
+ const int max_number_of_phys = sizeof(phy_info.Phy) / sizeof(phy_info.Phy[0]);
+ if (phy_info.bNumberOfPhys > max_number_of_phys)
return set_err(EIO, "CSMI_SAS_PHY_INFO: Bogus NumberOfPhys=%d", phy_info.bNumberOfPhys);
if (scsi_debugmode > 1) {
pout("CSMI_SAS_PHY_INFO: NumberOfPhys=%d\n", phy_info.bNumberOfPhys);
- for (int i = 0; i < phy_info.bNumberOfPhys; i++) {
+ for (int i = 0; i < max_number_of_phys; i++) {
const CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i];
const CSMI_SAS_IDENTIFY & id = pe.Identify, & at = pe.Attached;
+ if (id.bDeviceType == CSMI_SAS_NO_DEVICE_ATTACHED)
+ continue;
+
pout("Phy[%d] Port: 0x%02x\n", i, pe.bPortIdentifier);
pout(" Type: 0x%02x, 0x%02x\n", id.bDeviceType, at.bDeviceType);
pout(" InitProto: 0x%02x, 0x%02x\n", id.bInitiatorPortProtocol, at.bInitiatorPortProtocol);
return true;
}
-bool csmi_device::check_phy(const CSMI_SAS_PHY_INFO & phy_info, unsigned phy_no)
+unsigned csmi_device::get_ports_used()
{
- // Check Phy presence
- if (phy_no >= phy_info.bNumberOfPhys)
- return set_err(ENOENT, "Port %u does not exist (#ports: %d)", phy_no,
- phy_info.bNumberOfPhys);
+ CSMI_SAS_PHY_INFO phy_info;
+ if (!get_phy_info(phy_info))
+ return 0;
- const CSMI_SAS_PHY_ENTITY & phy_ent = phy_info.Phy[phy_no];
- if (phy_ent.Attached.bDeviceType == CSMI_SAS_NO_DEVICE_ATTACHED)
- return set_err(ENOENT, "No device on port %u", phy_no);
+ unsigned ports_used = 0;
+ for (unsigned i = 0; i < sizeof(phy_info.Phy) / sizeof(phy_info.Phy[0]); i++) {
+ const CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i];
+ if (pe.Identify.bDeviceType == CSMI_SAS_NO_DEVICE_ATTACHED)
+ continue;
+ if (pe.Attached.bDeviceType == CSMI_SAS_NO_DEVICE_ATTACHED)
+ continue;
+ switch (pe.Attached.bTargetPortProtocol) {
+ case CSMI_SAS_PROTOCOL_SATA:
+ case CSMI_SAS_PROTOCOL_STP:
+ break;
+ default:
+ continue;
+ }
- switch (phy_ent.Attached.bTargetPortProtocol) {
- case CSMI_SAS_PROTOCOL_SATA:
- case CSMI_SAS_PROTOCOL_STP:
- break;
- default:
- return set_err(ENOENT, "No SATA device on port %u (protocol: %u)",
- phy_no, phy_ent.Attached.bTargetPortProtocol);
+ if (pe.bPortIdentifier == 0xff)
+ // Older (<= 9.*) Intel RST driver
+ ports_used |= (1 << i);
+ else
+ ports_used |= (1 << pe.bPortIdentifier);
}
- return true;
+ return ports_used;
}
-bool csmi_device::select_phy(unsigned phy_no)
+
+bool csmi_device::select_port(int port)
{
CSMI_SAS_PHY_INFO phy_info;
if (!get_phy_info(phy_info))
return false;
+ // Find port
+ int max_port = -1, port_index = -1;
+ for (unsigned i = 0; i < sizeof(phy_info.Phy) / sizeof(phy_info.Phy[0]); i++) {
+ const CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i];
+ if (pe.Identify.bDeviceType == CSMI_SAS_NO_DEVICE_ATTACHED)
+ continue;
- if (!check_phy(phy_info, phy_no))
- return false;
+ if (pe.bPortIdentifier == 0xff) {
+ // Older (<= 9.*) Intel RST driver
+ max_port = phy_info.bNumberOfPhys - 1;
+ if (i >= phy_info.bNumberOfPhys)
+ break;
+ if ((int)i != port)
+ continue;
+ }
+ else {
+ if (pe.bPortIdentifier > max_port)
+ max_port = pe.bPortIdentifier;
+ if (pe.bPortIdentifier != port)
+ continue;
+ }
+
+ port_index = i;
+ break;
+ }
+
+ if (port_index < 0) {
+ if (port <= max_port)
+ return set_err(ENOENT, "Port %d is disabled", port);
+ else
+ return set_err(ENOENT, "Port %d does not exist (#ports: %d)", port,
+ max_port + 1);
+ }
+
+ const CSMI_SAS_PHY_ENTITY & phy_ent = phy_info.Phy[port_index];
+ if (phy_ent.Attached.bDeviceType == CSMI_SAS_NO_DEVICE_ATTACHED)
+ return set_err(ENOENT, "No device on port %d", port);
- m_phy_ent = phy_info.Phy[phy_no];
+ switch (phy_ent.Attached.bTargetPortProtocol) {
+ case CSMI_SAS_PROTOCOL_SATA:
+ case CSMI_SAS_PROTOCOL_STP:
+ break;
+ default:
+ return set_err(ENOENT, "No SATA device on port %d (protocol: %d)",
+ port, phy_ent.Attached.bTargetPortProtocol);
+ }
+
+ m_phy_ent = phy_ent;
return true;
}
win_csmi_device::win_csmi_device(smart_interface * intf, const char * dev_name,
const char * req_type)
: smart_device(intf, dev_name, "ata", req_type),
- m_fh(INVALID_HANDLE_VALUE), m_phy_no(0)
+ m_fh(INVALID_HANDLE_VALUE), m_port(-1)
{
}
bool win_csmi_device::open_scsi()
{
// Parse name
- unsigned contr_no = ~0, phy_no = ~0; int nc = -1;
+ unsigned contr_no = ~0, port = ~0; int nc = -1;
const char * name = skipdev(get_dev_name());
- if (!( sscanf(name, "csmi%u,%u%n", &contr_no, &phy_no, &nc) >= 0
- && nc == (int)strlen(name) && contr_no <= 9 && phy_no < 32) )
+ if (!( sscanf(name, "csmi%u,%u%n", &contr_no, &port, &nc) >= 0
+ && nc == (int)strlen(name) && contr_no <= 9 && port < 32) )
return set_err(EINVAL);
// Open controller handle
pout(" %s: successfully opened\n", devpath);
m_fh = h;
- m_phy_no = phy_no;
+ m_port = port;
return true;
}
return false;
// Get Phy info for this drive
- if (!select_phy(m_phy_no)) {
+ if (!select_port(m_port)) {
close();
return false;
}
} else
iop->resp_sense_len = 0;
- if ((iop->dxfer_len > 0) && (sb.spt.DataTransferLength > 0))
+ if (iop->dxfer_len > sb.spt.DataTransferLength)
iop->resid = iop->dxfer_len - sb.spt.DataTransferLength;
else
iop->resid = 0;
if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) {
int trunc = (iop->dxfer_len > 256) ? 1 : 0;
- pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
+ pout(" Incoming data, len=%d, resid=%d%s:\n", (int)iop->dxfer_len, iop->resid,
(trunc ? " [only first 256 bytes shown]" : ""));
dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
}
} else
iop->resp_sense_len = 0;
- if ((iop->dxfer_len > 0) && (sb.spt.DataTransferLength > 0))
+ if (iop->dxfer_len > sb.spt.DataTransferLength)
iop->resid = iop->dxfer_len - sb.spt.DataTransferLength;
else
iop->resid = 0;
if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) {
int trunc = (iop->dxfer_len > 256) ? 1 : 0;
- pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
+ pout(" Incoming data, len=%d, resid=%d%s:\n", (int)iop->dxfer_len, iop->resid,
(trunc ? " [only first 256 bytes shown]" : ""));
dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
}
smart_device * win_areca_ata_device::autodetect_open()
{
- int is_ata = 1;
-
// autodetect device type
- is_ata = arcmsr_get_dev_type();
+ int is_ata = arcmsr_get_dev_type();
if(is_ata < 0)
{
set_err(EIO);
return true;
}
+// AACRAID
+win_aacraid_device::win_aacraid_device(smart_interface * intf,
+ const char *dev_name, unsigned ctrnum, unsigned target, unsigned lun)
+: smart_device(intf, dev_name, "aacraid", "aacraid"),
+ m_ctrnum(ctrnum), m_lun(lun), m_target(target)
+{
+ set_info().info_name = strprintf("%s [aacraid_disk_%02d_%02d_%d]", dev_name, m_ctrnum, m_lun, m_target);
+ set_info().dev_type = strprintf("aacraid,%d,%d,%d", m_ctrnum, m_lun, m_target);
+}
+
+win_aacraid_device::~win_aacraid_device() throw()
+{
+}
+
+bool win_aacraid_device::open()
+{
+ if (is_open())
+ return true;
+
+ HANDLE hFh = CreateFile( get_dev_name(),
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ 0);
+ if (hFh == INVALID_HANDLE_VALUE)
+ return set_err(ENODEV, "Open failed, Error=%u", (unsigned)GetLastError());
+
+ set_fh(hFh);
+ return true;
+}
+
+bool win_aacraid_device::scsi_pass_through(struct scsi_cmnd_io *iop)
+{
+ int report = scsi_debugmode;
+ if (report > 0)
+ {
+ int k, j;
+ const unsigned char * ucp = iop->cmnd;
+ const char * np;
+ char buff[256];
+ const int sz = (int)sizeof(buff);
+ np = scsi_get_opcode_name(ucp[0]);
+ j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
+ for (k = 0; k < (int)iop->cmnd_len; ++k)
+ j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
+ if ((report > 1) &&
+ (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
+ int trunc = (iop->dxfer_len > 256) ? 1 : 0;
+
+ j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
+ "data, len=%d%s:\n", (int)iop->dxfer_len,
+ (trunc ? " [only first 256 bytes shown]" : ""));
+ dStrHex((const char *)iop->dxferp,
+ (trunc ? 256 : (int)iop->dxfer_len) , 1);
+ }
+ else
+ j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
+ pout("buff %s\n",buff);
+ }
+
+ char ioBuffer[1000];
+ SRB_IO_CONTROL * pSrbIO = (SRB_IO_CONTROL *) ioBuffer;
+ SCSI_REQUEST_BLOCK * pScsiIO = (SCSI_REQUEST_BLOCK *) (ioBuffer + sizeof(SRB_IO_CONTROL));
+ DWORD scsiRequestBlockSize = sizeof(SCSI_REQUEST_BLOCK);
+ char *pRequestSenseIO = (char *) (ioBuffer + sizeof(SRB_IO_CONTROL) + scsiRequestBlockSize);
+ DWORD dataOffset = (sizeof(SRB_IO_CONTROL) + scsiRequestBlockSize + 7) & 0xfffffff8;
+ char *pDataIO = (char *) (ioBuffer + dataOffset);
+ memset(pScsiIO, 0, scsiRequestBlockSize);
+ pScsiIO->Length = (USHORT) scsiRequestBlockSize;
+ pScsiIO->Function = SRB_FUNCTION_EXECUTE_SCSI;
+ pScsiIO->PathId = 0;
+ pScsiIO->TargetId = m_target;
+ pScsiIO->Lun = m_lun;
+ pScsiIO->CdbLength = (int)iop->cmnd_len;
+ switch(iop->dxfer_dir){
+ case DXFER_NONE:
+ pScsiIO->SrbFlags = SRB_NoDataXfer;
+ break;
+ case DXFER_FROM_DEVICE:
+ pScsiIO->SrbFlags |= SRB_DataIn;
+ break;
+ case DXFER_TO_DEVICE:
+ pScsiIO->SrbFlags |= SRB_DataOut;
+ break;
+ default:
+ pout("aacraid: bad dxfer_dir\n");
+ return set_err(EINVAL, "aacraid: bad dxfer_dir\n");
+ }
+ pScsiIO->DataTransferLength = (ULONG)iop->dxfer_len;
+ pScsiIO->TimeOutValue = iop->timeout;
+ UCHAR *pCdb = (UCHAR *) pScsiIO->Cdb;
+ memcpy(pCdb, iop->cmnd, 16);
+ if (iop->max_sense_len){
+ memset(pRequestSenseIO, 0, iop->max_sense_len);
+ }
+ if (pScsiIO->SrbFlags & SRB_FLAGS_DATA_OUT){
+ memcpy(pDataIO, iop->dxferp, iop->dxfer_len);
+ }
+ else if (pScsiIO->SrbFlags & SRB_FLAGS_DATA_IN){
+ memset(pDataIO, 0, iop->dxfer_len);
+ }
+
+ DWORD bytesReturned = 0;
+ memset(pSrbIO, 0, sizeof(SRB_IO_CONTROL));
+ pSrbIO->HeaderLength = sizeof(SRB_IO_CONTROL);
+ memcpy(pSrbIO->Signature, "AACAPI", 7);
+ pSrbIO->ControlCode = ARCIOCTL_SEND_RAW_SRB;
+ pSrbIO->Length = (dataOffset + iop->dxfer_len - sizeof(SRB_IO_CONTROL) + 7) & 0xfffffff8;
+ pSrbIO->Timeout = 3*60;
+
+ if (!DeviceIoControl(
+ get_fh(),
+ IOCTL_SCSI_MINIPORT,
+ ioBuffer,
+ sizeof(SRB_IO_CONTROL) + pSrbIO->Length,
+ ioBuffer,
+ sizeof(SRB_IO_CONTROL) + pSrbIO->Length,
+ &bytesReturned,
+ NULL)
+ ) {
+ return set_err(EIO, "ARCIOCTL_SEND_RAW_SRB failed, Error=%u", (unsigned)GetLastError());
+ }
+
+ iop->scsi_status = pScsiIO->ScsiStatus;
+ if (SCSI_STATUS_CHECK_CONDITION & iop->scsi_status) {
+ int slen = sizeof(pRequestSenseIO) + 8;
+ if (slen > (int)sizeof(pRequestSenseIO))
+ slen = sizeof(pRequestSenseIO);
+ if (slen > (int)iop->max_sense_len)
+ slen = (int)iop->max_sense_len;
+ memcpy(iop->sensep, pRequestSenseIO, slen);
+ iop->resp_sense_len = slen;
+ if (report) {
+ if (report > 1) {
+ pout(" >>> Sense buffer, len=%d:\n", slen);
+ dStrHex(iop->sensep, slen , 1);
+ }
+ if ((iop->sensep[0] & 0x7f) > 0x71)
+ pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
+ iop->scsi_status, iop->sensep[1] & 0xf,
+ iop->sensep[2], iop->sensep[3]);
+ else
+ pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
+ iop->scsi_status, iop->sensep[2] & 0xf,
+ iop->sensep[12], iop->sensep[13]);
+ }
+ }
+ else {
+ iop->resp_sense_len = 0;
+ }
+
+ if (iop->dxfer_dir == DXFER_FROM_DEVICE){
+ memcpy(iop->dxferp,pDataIO, iop->dxfer_len);
+ }
+ if((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)){
+ int trunc = (iop->dxfer_len > 256) ? 1 : 0;
+ pout(" Incoming data, len=%d, resid=%d%s:\n", (int)iop->dxfer_len, iop->resid,
+ (trunc ? " [only first 256 bytes shown]" : ""));
+ dStrHex((CHAR*)pDataIO, (trunc ? 256 : (int)(iop->dxfer_len)) , 1);
+ }
+ return true;
+}
//////////////////////////////////////////////////////////////////////////////////////////////////