*
* Home page of code is: http://www.smartmontools.org
*
-<<<<<<< HEAD
- * Copyright (C) 2004-16 Christian Franke
-=======
- * Copyright (C) 2004-15 Christian Franke
->>>>>>> 3d8ad6fa4529eb02ae1391a1e937bf57aad3fb74
+ * Copyright (C) 2004-18 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
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * You should have received a copy of the GNU General Public License
- * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#define WINVER 0x0502
#define _WIN32_WINNT WINVER
-#include "int64.h"
#include "atacmds.h"
#include "scsicmds.h"
#include "nvmecmds.h"
#include "utility.h"
-#include "smartctl.h" // TODO: Do not use smartctl only variables here
#include "dev_interface.h"
#include "dev_ata_cmd_set.h"
#include "dev_areca.h"
#include "os_win32/wmiquery.h"
+#include "os_win32/popen.h"
+
+// TODO: Move from smartctl.h to other include file
+extern unsigned char failuretest_permissive;
#include <errno.h>
#define strnicmp strncasecmp
#endif
-<<<<<<< HEAD
-const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 4293 2016-04-14 19:33:05Z chrfranke $";
-=======
-const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 4098 2015-05-30 16:37:37Z chrfranke $";
->>>>>>> 3d8ad6fa4529eb02ae1391a1e937bf57aad3fb74
+const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 4848 2018-12-05 18:30:46Z chrfranke $";
/////////////////////////////////////////////////////////////////////////////
// Windows I/O-controls, some declarations are missing in the include files
ASSERT_SIZEOF(STORAGE_PROPERTY_QUERY, 8+1+3);
+// IOCTL_STORAGE_QUERY_PROPERTY: Windows 10 enhancements
+
+namespace win10 {
+
+ // enum STORAGE_PROPERTY_ID: new values
+ const STORAGE_PROPERTY_ID StorageAdapterProtocolSpecificProperty = (STORAGE_PROPERTY_ID)49;
+ const STORAGE_PROPERTY_ID StorageDeviceProtocolSpecificProperty = (STORAGE_PROPERTY_ID)50;
+
+ typedef enum _STORAGE_PROTOCOL_TYPE {
+ ProtocolTypeUnknown = 0,
+ ProtocolTypeScsi,
+ ProtocolTypeAta,
+ ProtocolTypeNvme,
+ ProtocolTypeSd
+ } STORAGE_PROTOCOL_TYPE;
+
+ typedef enum _STORAGE_PROTOCOL_NVME_DATA_TYPE {
+ NVMeDataTypeUnknown = 0,
+ NVMeDataTypeIdentify,
+ NVMeDataTypeLogPage,
+ NVMeDataTypeFeature
+ } STORAGE_PROTOCOL_NVME_DATA_TYPE;
+
+ typedef struct _STORAGE_PROTOCOL_SPECIFIC_DATA {
+ STORAGE_PROTOCOL_TYPE ProtocolType;
+ ULONG DataType;
+ ULONG ProtocolDataRequestValue;
+ ULONG ProtocolDataRequestSubValue;
+ ULONG ProtocolDataOffset;
+ ULONG ProtocolDataLength;
+ ULONG FixedProtocolReturnData;
+ ULONG Reserved[3];
+ } STORAGE_PROTOCOL_SPECIFIC_DATA;
+
+ ASSERT_SIZEOF(STORAGE_PROTOCOL_SPECIFIC_DATA, 40);
+
+} // namespace win10
+
+
// IOCTL_STORAGE_PREDICT_FAILURE
ASSERT_CONST(IOCTL_STORAGE_PREDICT_FAILURE, 0x002d1100);
assert(num_out == sizeof(GETVERSIONINPARAMS));
if (ata_debugmode > 1) {
- pout(" SMART_GET_VERSION suceeded, bytes returned: %u\n"
+ pout(" SMART_GET_VERSION succeeded, bytes returned: %u\n"
" Vers = %d.%d, Caps = 0x%x, DeviceMap = 0x%02x\n",
(unsigned)num_out, vers.bVersion, vers.bRevision,
(unsigned)vers.fCapabilities, vers.bIDEDeviceMap);
}
if (ata_debugmode > 1) {
- pout(" %s suceeded, bytes returned: %u (buffer %u)\n", name,
+ pout(" %s succeeded, bytes returned: %u (buffer %u)\n", name,
(unsigned)num_out, (unsigned)outpar->cBufferSize);
print_ide_regs_io(regs, (regs->bFeaturesReg == ATA_SMART_STATUS ?
(const IDEREGS *)(outpar->bBuffer) : NULL));
return 0;
}
-/////////////////////////////////////////////////////////////////////////////
-//// 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;
-};
-
-
/////////////////////////////////////////////////////////////////////////////
// IDE PASS THROUGH (2000, XP, undocumented)
}
if (ata_debugmode > 1) {
- pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %u (buffer %u)\n",
+ pout(" IOCTL_IDE_PASS_THROUGH succeeded, bytes returned: %u (buffer %u)\n",
(unsigned)num_out, (unsigned)buf->DataBufferSize);
print_ide_regs_io(regs, &buf->IdeReg);
}
//ab.apt.PathId = 0;
//ab.apt.TargetId = 0;
//ab.apt.Lun = 0;
- ab.apt.TimeOutValue = 10;
+ ab.apt.TimeOutValue = 60; // seconds
unsigned size = offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS, ucDataBuf);
ab.apt.DataBufferOffset = size;
return -1;
}
-<<<<<<< HEAD
// Check and copy data
if (datasize > 0) {
if ( num_out != size
if (ata_debugmode) {
pout(" IOCTL_ATA_PASS_THROUGH output data missing (%u)\n", (unsigned)num_out);
print_ide_regs_io(regs, ctfregs);
-=======
- 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;
- case 0x64: w = (ws ? "win10" : "w10srv"); break;
->>>>>>> 3d8ad6fa4529eb02ae1391a1e937bf57aad3fb74
}
errno = EIO;
return -1;
}
if (ata_debugmode > 1) {
- pout(" IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %u\n", (unsigned)num_out);
+ pout(" IOCTL_ATA_PASS_THROUGH succeeded, bytes returned: %u\n", (unsigned)num_out);
print_ide_regs_io(regs, ctfregs);
}
*regs = *ctfregs;
ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS)-1+512);
memset(&sb, 0, sizeof(sb));
-<<<<<<< HEAD
unsigned size;
if (datasize > 0) {
if (datasize > (int)sizeof(sb.space)+1) {
sb.srbc.Length = sizeof(SENDCMDINPARAMS)-1 + size;
sb.params.in.irDriveRegs = *regs;
sb.params.in.cBufferSize = size;
-=======
-// Return value for device detection functions
-enum win_dev_type { DEV_UNKNOWN = 0, DEV_ATA, DEV_SCSI, DEV_SAT, DEV_USB };
->>>>>>> 3d8ad6fa4529eb02ae1391a1e937bf57aad3fb74
// Call miniport ioctl
size += sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)-1;
}
if (ata_debugmode > 1) {
- pout(" IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %u (buffer %u)\n", name,
+ pout(" IOCTL_SCSI_MINIPORT_%s succeeded, bytes returned: %u (buffer %u)\n", name,
(unsigned)num_out, (unsigned)sb.params.out.cBufferSize);
print_ide_regs_io(regs, (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS ?
(const IDEREGS *)(sb.params.out.bBuffer) : 0));
return -1;
}
-<<<<<<< HEAD
// Copy data
if (datasize > 0)
memcpy(data, sb.buffer, datasize);
if (ata_debugmode > 1) {
- pout(" ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %u\n", (unsigned)num_out);
+ pout(" ATA via IOCTL_SCSI_MINIPORT succeeded, bytes returned: %u\n", (unsigned)num_out);
print_ide_regs_io(regs, &sb.regs);
-=======
- name = skipdev(name);
-#define ARECA_MAX_CTLR_NUM 16
- n1 = -1;
- int ctlrindex = 0;
- if (sscanf(name, "arcmsr%d%n", &ctlrindex, &n1) >= 1 && n1 == (int)strlen(name)) {
- /*
- 1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[ARECA_MAX_CTLR_NUM]:" and
- 2. map arcmsrX into "\\\\.\\scsiX"
- */
- for (int idx = 0; idx < ARECA_MAX_CTLR_NUM; idx++) {
- memset(devpath, 0, sizeof(devpath));
- snprintf(devpath, sizeof(devpath), "\\\\.\\scsi%d:", idx);
- win_areca_ata_device *arcdev = new win_areca_ata_device(this, devpath, disknum, encnum);
- if(arcdev->arcmsr_probe()) {
- if(ctlrindex-- == 0) {
- return arcdev;
- }
- }
- delete arcdev;
- }
- set_err(ENOENT, "No Areca controller found");
- }
- 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;
->>>>>>> 3d8ad6fa4529eb02ae1391a1e937bf57aad3fb74
}
*regs = sb.regs;
return 0;
}
-<<<<<<< HEAD
-=======
-std::string win_smart_interface::get_valid_custom_dev_types_str()
-{
- return "aacraid,H,L,ID, areca,N[/E]";
-}
->>>>>>> 3d8ad6fa4529eb02ae1391a1e937bf57aad3fb74
/////////////////////////////////////////////////////////////////////////////
return -1;
}
if (ata_debugmode > 1)
- pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT suceeded\n");
+ pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT succeeded\n");
return 0;
}
/////////////////////////////////////////////////////////////////////////////
// IOCTL_STORAGE_QUERY_PROPERTY
-<<<<<<< HEAD
union STORAGE_DEVICE_DESCRIPTOR_DATA {
STORAGE_DEVICE_DESCRIPTOR desc;
char raw[256];
pout(" IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%u\n", (unsigned)GetLastError());
errno = ENOSYS;
return -1;
-=======
- 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))) {
- set_err(EINVAL, "Unable to read USB device ID");
- return 0;
- }
- // Get type name for this ID
- const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id);
- if (!usbtype)
- return 0;
- // Return SAT/USB device for this type
- return get_sat_device(usbtype, new win_scsi_device(this, name, ""));
->>>>>>> 3d8ad6fa4529eb02ae1391a1e937bf57aad3fb74
}
if (ata_debugmode > 1 || scsi_debugmode > 1) {
// IOCTL_STORAGE_PREDICT_FAILURE
// Call IOCTL_STORAGE_PREDICT_FAILURE, return PredictFailure value
-// or -1 on error, opionally return VendorSpecific data.
+// or -1 on error, optionally return VendorSpecific data.
// (This works without admin rights)
static int storage_predict_failure_ioctl(HANDLE hdevice, char * data = 0)
return -1;
}
-<<<<<<< HEAD
if (ata_debugmode > 1) {
pout(" IOCTL_STORAGE_PREDICT_FAILURE returns:\n"
" PredictFailure: 0x%08x\n"
memcpy(data, pred.VendorSpecific, sizeof(pred.VendorSpecific));
return (!pred.PredictFailure ? 0 : 1);
}
-=======
- // Set valid types
- bool ata, scsi, sat, usb, csmi;
- if (!type) {
- ata = scsi = usb = sat = csmi = true;
- }
- else {
- 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], sat[,pd], usb[,pd], csmi, pd",
- type);
- return false;
- }
- }
-
- char name[20];
-
- 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};
-
- for (int i = 0; i < 128; i++) {
- if (pd)
- snprintf(name, sizeof(name), "/dev/pd%d", i);
- else if (i + 'a' <= 'z')
- snprintf(name, sizeof(name), "/dev/sd%c", i + 'a');
- else
- snprintf(name, sizeof(name), "/dev/sd%c%c",
- i / ('z'-'a'+1) - 1 + 'a',
- i % ('z'-'a'+1) + 'a');
->>>>>>> 3d8ad6fa4529eb02ae1391a1e937bf57aad3fb74
// Build IDENTIFY information from STORAGE_DEVICE_DESCRIPTOR
// others return it as ProductId only.
char model[sizeof(id->model) + 1] = "";
-<<<<<<< HEAD
unsigned i = 0;
if (data.desc.VendorIdOffset) {
for ( ;i < sizeof(model)-1 && data.raw[data.desc.VendorIdOffset+i]; i++)
model[i] = data.raw[data.desc.VendorIdOffset+i];
}
-=======
- 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)
- continue;
- {
- // 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))
- continue;
- // Get type name for this ID
- const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id);
- if (!usbtype)
- continue;
- // Return SAT/USB device for this type
- ata_device * dev = get_sat_device(usbtype, new win_scsi_device(this, name, ""));
- if (!dev)
- continue;
- devlist.push_back(dev);
- }
- break;
->>>>>>> 3d8ad6fa4529eb02ae1391a1e937bf57aad3fb74
if (data.desc.ProductIdOffset) {
while (i > 1 && model[i-2] == ' ') // Keep last blank from VendorId
std::string prev_usb_ant;
std::string prev_ant, ant, dep;
- const regular_expression regex("^.*PnPEntity\\.DeviceID=\"([^\"]*)\"", REG_EXTENDED);
+ const regular_expression regex("^.*PnPEntity\\.DeviceID=\"([^\"]*)\"");
while (we.next(wo)) {
prev_ant = ant;
pout(" %s:\n", ant.c_str());
// Extract DeviceID
- regmatch_t match[2];
+ regular_expression::match_range match[2];
if (!(regex.execute(dep.c_str(), 2, match) && match[1].rm_so >= 0)) {
if (debug)
pout(" | (\"%s\")\n", dep.c_str());
// 3ware RAID if vendor id present
m_is_3ware = (vers_ex.wIdentifier == SMART_VENDOR_3WARE);
- unsigned long portmap = 0;
+ unsigned portmap = 0;
if (port >= 0 && devmap >= 0) {
// 3ware RAID: check vendor id
if (!m_is_3ware) {
{
// 3ware RAID: update devicemap first
-
if (!update_3ware_devicemap_ioctl(h)) {
if ( smart_get_version(h, &vers_ex) >= 0
&& vers_ex.wIdentifier == SMART_VENDOR_3WARE )
portmap = vers_ex.dwDeviceMapEx;
}
// Check port existence
- if (!(portmap & (1L << port))) {
+ if (!(portmap & (1U << port))) {
if (!is_permissive()) {
close();
return set_err(ENOENT, "%s: Port %d is empty or does not exist", devpath, port);
: virtual public /*extends*/ smart_device
{
public:
+ enum { max_number_of_ports = 32 };
+
/// Get bitmask of used ports
unsigned get_ports_used();
: 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);
+ typedef signed char port_2_index_map[max_number_of_ports];
+
+ /// Get phy info and port mapping, return #ports or -1 on error
+ int get_phy_info(CSMI_SAS_PHY_INFO & phy_info, port_2_index_map & p2i);
/// Select physical drive
bool select_port(int port);
/////////////////////////////////////////////////////////////////////////////
-bool csmi_device::get_phy_info(CSMI_SAS_PHY_INFO & phy_info)
+int csmi_device::get_phy_info(CSMI_SAS_PHY_INFO & phy_info, port_2_index_map & p2i)
{
+ // max_number_of_ports must match CSMI_SAS_PHY_INFO.Phy[] array size
+ typedef char ASSERT_phy_info_size[
+ (int)(sizeof(phy_info.Phy) / sizeof(phy_info.Phy[0])) == max_number_of_ports ? 1 : -1]
+ ATTR_UNUSED;
+
// Get driver info to check CSMI support
CSMI_SAS_DRIVER_INFO_BUFFER driver_info_buf;
memset(&driver_info_buf, 0, sizeof(driver_info_buf));
if (!csmi_ioctl(CC_CSMI_SAS_GET_DRIVER_INFO, &driver_info_buf.IoctlHeader, sizeof(driver_info_buf)))
- return false;
+ return -1;
if (scsi_debugmode > 1) {
const CSMI_SAS_DRIVER_INFO & driver_info = driver_info_buf.Information;
CSMI_SAS_PHY_INFO_BUFFER phy_info_buf;
memset(&phy_info_buf, 0, sizeof(phy_info_buf));
if (!csmi_ioctl(CC_CSMI_SAS_GET_PHY_INFO, &phy_info_buf.IoctlHeader, sizeof(phy_info_buf)))
- return false;
+ return -1;
phy_info = phy_info_buf.Information;
- 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 (phy_info.bNumberOfPhys > max_number_of_ports) {
+ set_err(EIO, "CSMI_SAS_PHY_INFO: Bogus NumberOfPhys=%d", phy_info.bNumberOfPhys);
+ return -1;
+ }
+
+ // Create port -> index map
+ // IRST Release
+ // Phy[i].Value 9.x 10.x 14.8 15.2 16.0
+ // ----------------------------------------------------------
+ // bPortIdentifier 0xff 0xff port 0x00 port
+ // Identify.bPhyIdentifier index? index? index index port
+ // Attached.bPhyIdentifier 0x00 0x00 0x00 index 0x00
+ //
+ // Empty ports with hotplug support may appear in Phy[].
+
+ int number_of_ports;
+ for (int mode = 0; ; mode++) {
+ for (int i = 0; i < max_number_of_ports; i++)
+ p2i[i] = -1;
+
+ number_of_ports = 0;
+ bool found = false;
+ for (int i = 0; i < max_number_of_ports; i++) {
+ const CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i];
+ if (pe.Identify.bDeviceType == CSMI_SAS_NO_DEVICE_ATTACHED)
+ continue;
+
+ // Try to detect which field contains the actual port number.
+ // Use a bPhyIdentifier or the bPortIdentifier if unique
+ // and not always identical to table index, otherwise use index.
+ int port;
+ switch (mode) {
+ case 0: port = pe.Attached.bPhyIdentifier; break;
+ case 1: port = pe.Identify.bPhyIdentifier; break;
+ case 2: port = pe.bPortIdentifier; break;
+ default: port = i; break;
+ }
+ if (!(port < max_number_of_ports && p2i[port] == -1)) {
+ found = false;
+ break;
+ }
+
+ p2i[port] = i;
+ if (number_of_ports <= port)
+ number_of_ports = port + 1;
+ if (port != i)
+ found = true;
+ }
+
+ if (found || mode > 2)
+ break;
+ }
if (scsi_debugmode > 1) {
pout("CSMI_SAS_PHY_INFO: NumberOfPhys=%d\n", phy_info.bNumberOfPhys);
- for (int i = 0; i < max_number_of_phys; i++) {
+ for (int i = 0; i < max_number_of_ports; 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);
+ int port = -1;
+ for (int p = 0; p < max_number_of_ports && port < 0; p++) {
+ if (p2i[p] == i)
+ port = p;
+ }
+
+ pout("Phy[%d] Port: %d\n", i, port);
pout(" Type: 0x%02x, 0x%02x\n", id.bDeviceType, at.bDeviceType);
pout(" InitProto: 0x%02x, 0x%02x\n", id.bInitiatorPortProtocol, at.bInitiatorPortProtocol);
pout(" TargetProto: 0x%02x, 0x%02x\n", id.bTargetPortProtocol, at.bTargetPortProtocol);
+ pout(" PortIdent: 0x%02x\n", pe.bPortIdentifier);
pout(" PhyIdent: 0x%02x, 0x%02x\n", id.bPhyIdentifier, at.bPhyIdentifier);
const unsigned char * b = id.bSASAddress;
pout(" SASAddress: %02x %02x %02x %02x %02x %02x %02x %02x, ",
}
}
- return true;
+ return number_of_ports;
}
unsigned csmi_device::get_ports_used()
{
CSMI_SAS_PHY_INFO phy_info;
- if (!get_phy_info(phy_info))
+ port_2_index_map p2i;
+ int number_of_ports = get_phy_info(phy_info, p2i);
+ if (number_of_ports < 0)
return 0;
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)
+ for (int p = 0; p < max_number_of_ports; p++) {
+ int i = p2i[p];
+ if (i < 0)
continue;
+ const CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i];
if (pe.Attached.bDeviceType == CSMI_SAS_NO_DEVICE_ATTACHED)
continue;
switch (pe.Attached.bTargetPortProtocol) {
continue;
}
- if (pe.bPortIdentifier == 0xff)
- // Older (<= 9.*) Intel RST driver
- ports_used |= (1 << i);
- else
- ports_used |= (1 << pe.bPortIdentifier);
+ ports_used |= (1U << p);
}
return ports_used;
}
-
bool csmi_device::select_port(int port)
{
+ if (!(0 <= port && port < max_number_of_ports))
+ return set_err(EINVAL, "Invalid port number %d", port);
+
CSMI_SAS_PHY_INFO phy_info;
- if (!get_phy_info(phy_info))
+ port_2_index_map p2i;
+ int number_of_ports = get_phy_info(phy_info, p2i);
+ if (number_of_ports < 0)
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 (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;
- }
-
+ int port_index = p2i[port];
if (port_index < 0) {
- if (port <= max_port)
+ if (port < number_of_ports)
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);
+ number_of_ports);
}
const CSMI_SAS_PHY_ENTITY & phy_ent = phy_info.Phy[port_index];
ata_device::supports_output_regs |
ata_device::supports_multi_sector |
ata_device::supports_48bit,
- "CMSI")
+ "CSMI")
)
return false;
// TODO: Check ptru_buf->Status.uDataBytes
memcpy(in.buffer, pthru_buf->bDataBuffer, in.size);
-<<<<<<< HEAD
-=======
-// 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)
-{
- if (!(data->desc.VendorIdOffset && data->desc.ProductIdOffset))
- return false;
- const char * vendor = data->raw + data->desc.VendorIdOffset;
- if (!(!strnicmp(vendor, "Intel", 5) && strspn(vendor+5, " ") == strlen(vendor+5)))
- return false;
- if (strnicmp(data->raw + data->desc.ProductIdOffset, "Raid ", 5))
- return false;
->>>>>>> 3d8ad6fa4529eb02ae1391a1e937bf57aad3fb74
return true;
}
win_csmi_device(smart_interface * intf, const char * dev_name,
const char * req_type);
-<<<<<<< HEAD
virtual ~win_csmi_device() throw();
virtual bool open();
virtual bool close();
-=======
- // Newer BusType* values are missing in older includes
- 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;
+ virtual bool is_open() const;
- 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;
->>>>>>> 3d8ad6fa4529eb02ae1391a1e937bf57aad3fb74
-
- virtual bool is_open() const;
-
- bool open_scsi();
+ bool open_scsi();
protected:
virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer,
}
-// Run a command, write stdout to dataout
-// TODO: Combine with daemon_win32.cpp:daemon_spawn()
-
-static int run_cmd(const char * cmd, char * dataout, int outsize)
-{
- // Create stdout pipe
- SECURITY_ATTRIBUTES sa = {sizeof(sa), 0, TRUE};
- HANDLE pipe_out_w, h;
- if (!CreatePipe(&h, &pipe_out_w, &sa/*inherit*/, outsize))
- return -1;
- HANDLE self = GetCurrentProcess();
- HANDLE pipe_out_r;
- if (!DuplicateHandle(self, h, self, &pipe_out_r,
- GENERIC_READ, FALSE/*!inherit*/, DUPLICATE_CLOSE_SOURCE)) {
- CloseHandle(pipe_out_w);
- return -1;
- }
- HANDLE pipe_err_w;
- if (!DuplicateHandle(self, pipe_out_w, self, &pipe_err_w,
- 0, TRUE/*inherit*/, DUPLICATE_SAME_ACCESS)) {
- CloseHandle(pipe_out_r); CloseHandle(pipe_out_w);
- return -1;
- }
-
- // Create process
- STARTUPINFO si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si);
- si.hStdInput = INVALID_HANDLE_VALUE;
- si.hStdOutput = pipe_out_w; si.hStdError = pipe_err_w;
- si.dwFlags = STARTF_USESTDHANDLES;
- PROCESS_INFORMATION pi;
- if (!CreateProcess(
- NULL, const_cast<char *>(cmd),
- NULL, NULL, TRUE/*inherit*/,
- CREATE_NO_WINDOW/*do not create a new console window*/,
- NULL, NULL, &si, &pi)) {
- CloseHandle(pipe_err_w); CloseHandle(pipe_out_r); CloseHandle(pipe_out_w);
- return -1;
- }
- CloseHandle(pi.hThread);
- CloseHandle(pipe_err_w); CloseHandle(pipe_out_w);
-
- // Copy stdout to output buffer
- int i = 0;
- while (i < outsize) {
- DWORD num_read;
- if (!ReadFile(pipe_out_r, dataout+i, outsize-i, &num_read, NULL) || num_read == 0)
- break;
- i += num_read;
- }
- CloseHandle(pipe_out_r);
- // Wait for process
- WaitForSingleObject(pi.hProcess, INFINITE);
- CloseHandle(pi.hProcess);
- return i;
-}
-
-
static const char * findstr(const char * str, const char * sub)
{
const char * s = strstr(str, sub);
snprintf(cmd, sizeof(cmd), "tw_cli /%s show all", name+n1);
if (ata_debugmode > 1)
pout("%s: Run: \"%s\"\n", name, cmd);
- size = run_cmd(cmd, buffer, sizeof(buffer));
+ FILE * f = popen(cmd, "rb");
+ if (f) {
+ size = fread(buffer, 1, sizeof(buffer), f);
+ pclose(f);
+ }
}
else {
return set_err(EINVAL);
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);
+ dStrHex(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);
+ pout("buff %s\n",buff);
}
char ioBuffer[1000];
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);
+ dStrHex((const uint8_t *)pDataIO, (trunc ? 256 : (int)(iop->dxfer_len)) , 1);
}
return true;
}
return true;
}
-// Check if NVMe pass-through works
+// Check if NVMe DeviceIoControl(IOCTL_SCSI_MINIPORT) pass-through works.
+// On Win10 and later that returns false with an errorNumber of 1
+// ("Incorrect function"). Win10 has new pass-through:
+// DeviceIoControl(IOCTL_STORAGE_PROTOCOL_COMMAND). However for commonly
+// requested NVMe commands like Identify and Get Features Microsoft want
+// "Protocol specific queries" sent.
bool win_nvme_device::probe()
{
smartmontools::nvme_id_ctrl id_ctrl;
// Set NVMe command
pthru->SrbIoCtrl.HeaderLength = sizeof(SRB_IO_CONTROL);
- memcpy(pthru->SrbIoCtrl.Signature, NVME_SIG_STR, sizeof(NVME_SIG_STR));
+ memcpy(pthru->SrbIoCtrl.Signature, NVME_SIG_STR, sizeof(NVME_SIG_STR)-1);
pthru->SrbIoCtrl.Timeout = 60;
pthru->SrbIoCtrl.ControlCode = NVME_PASS_THROUGH_SRB_IO_CODE;
pthru->SrbIoCtrl.ReturnCode = 0;
}
+/////////////////////////////////////////////////////////////////////////////
+// win10_nvme_device
+
+class win10_nvme_device
+: public /*implements*/ nvme_device,
+ public /*extends*/ win_smart_device
+{
+public:
+ win10_nvme_device(smart_interface * intf, const char * dev_name,
+ const char * req_type, unsigned nsid);
+
+ virtual bool open();
+
+ virtual bool nvme_pass_through(const nvme_cmd_in & in, nvme_cmd_out & out);
+
+private:
+ bool open(int phydrive);
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+win10_nvme_device::win10_nvme_device(smart_interface * intf, const char * dev_name,
+ const char * req_type, unsigned nsid)
+: smart_device(intf, dev_name, "nvme", req_type),
+ nvme_device(nsid)
+{
+}
+
+bool win10_nvme_device::open()
+{
+ // TODO: Use common /dev/ parsing functions
+ const char * name = skipdev(get_dev_name()); int len = strlen(name);
+ // sd[a-z]([a-z])? => Physical drive 0-701
+ char drive[2 + 1] = ""; int n = -1;
+ if (sscanf(name, "sd%2[a-z]%n", drive, &n) == 1 && n == len)
+ return open(sdxy_to_phydrive(drive));
+
+ // pdN => Physical drive N
+ int phydrive = -1; n = -1;
+ if (sscanf(name, "pd%d%n", &phydrive, &n) == 1 && phydrive >= 0 && n == len)
+ return open(phydrive);
+
+ return set_err(EINVAL);
+}
+
+bool win10_nvme_device::open(int phydrive)
+{
+ // TODO: Use common open function for all devices using "\\.\PhysicalDriveN"
+ char devpath[64];
+ snprintf(devpath, sizeof(devpath) - 1, "\\\\.\\PhysicalDrive%d", phydrive);
+
+ // No GENERIC_READ/WRITE access required, this works without admin rights
+ HANDLE h = CreateFileA(devpath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, (HANDLE)0);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ long err = GetLastError();
+ if (nvme_debugmode > 1)
+ pout(" %s: Open failed, Error=%ld\n", devpath, err);
+ if (err == ERROR_FILE_NOT_FOUND)
+ set_err(ENOENT, "%s: not found", devpath);
+ else if (err == ERROR_ACCESS_DENIED)
+ set_err(EACCES, "%s: access denied", devpath);
+ else
+ set_err(EIO, "%s: Error=%ld", devpath, err);
+ return false;
+ }
+
+ if (nvme_debugmode > 1)
+ pout(" %s: successfully opened\n", devpath);
+
+ set_fh(h);
+
+ // Use broadcast namespace if no NSID specified
+ // TODO: Get NSID of current device
+ if (!get_nsid())
+ set_nsid(0xffffffff);
+ return true;
+}
+
+struct STORAGE_PROTOCOL_SPECIFIC_QUERY_WITH_BUFFER
+{
+ struct { // STORAGE_PROPERTY_QUERY without AdditionalsParameters[1]
+ STORAGE_PROPERTY_ID PropertyId;
+ STORAGE_QUERY_TYPE QueryType;
+ } PropertyQuery;
+ win10::STORAGE_PROTOCOL_SPECIFIC_DATA ProtocolSpecific;
+ BYTE DataBuffer[1];
+};
+
+bool win10_nvme_device::nvme_pass_through(const nvme_cmd_in & in, nvme_cmd_out & out)
+{
+ // Create buffer with appropriate size
+ raw_buffer spsq_raw_buf(offsetof(STORAGE_PROTOCOL_SPECIFIC_QUERY_WITH_BUFFER, DataBuffer) + in.size);
+ STORAGE_PROTOCOL_SPECIFIC_QUERY_WITH_BUFFER * spsq =
+ reinterpret_cast<STORAGE_PROTOCOL_SPECIFIC_QUERY_WITH_BUFFER *>(spsq_raw_buf.data());
+
+ // Set NVMe specific STORAGE_PROPERTY_QUERY
+ spsq->PropertyQuery.QueryType = PropertyStandardQuery;
+ spsq->ProtocolSpecific.ProtocolType = win10::ProtocolTypeNvme;
+
+ switch (in.opcode) {
+ case smartmontools::nvme_admin_identify:
+ if (!in.nsid) // Identify controller
+ spsq->PropertyQuery.PropertyId = win10::StorageAdapterProtocolSpecificProperty;
+ else
+ spsq->PropertyQuery.PropertyId = win10::StorageDeviceProtocolSpecificProperty;
+ spsq->ProtocolSpecific.DataType = win10::NVMeDataTypeIdentify;
+ spsq->ProtocolSpecific.ProtocolDataRequestValue = in.cdw10;
+ break;
+ case smartmontools::nvme_admin_get_log_page:
+ spsq->PropertyQuery.PropertyId = win10::StorageDeviceProtocolSpecificProperty;
+ spsq->ProtocolSpecific.DataType = win10::NVMeDataTypeLogPage;
+ spsq->ProtocolSpecific.ProtocolDataRequestValue = in.cdw10 & 0xff; // LID only ?
+ break;
+ // TODO: nvme_admin_get_features
+ default:
+ return set_err(ENOSYS, "NVMe admin command 0x%02x not supported", in.opcode);
+ }
+
+ spsq->ProtocolSpecific.ProtocolDataRequestSubValue = in.nsid; // ?
+ spsq->ProtocolSpecific.ProtocolDataOffset = sizeof(spsq->ProtocolSpecific);
+ spsq->ProtocolSpecific.ProtocolDataLength = in.size;
+
+ if (in.direction() & nvme_cmd_in::data_out)
+ memcpy(spsq->DataBuffer, in.buffer, in.size);
+
+ if (nvme_debugmode > 1)
+ pout(" [STORAGE_QUERY_PROPERTY: Id=%u, Type=%u, Value=0x%08x, SubVal=0x%08x]\n",
+ (unsigned)spsq->PropertyQuery.PropertyId,
+ (unsigned)spsq->ProtocolSpecific.DataType,
+ (unsigned)spsq->ProtocolSpecific.ProtocolDataRequestValue,
+ (unsigned)spsq->ProtocolSpecific.ProtocolDataRequestSubValue);
+
+ // Call IOCTL_STORAGE_QUERY_PROPERTY
+ DWORD num_out = 0;
+ long err = 0;
+ if (!DeviceIoControl(get_fh(), IOCTL_STORAGE_QUERY_PROPERTY,
+ spsq, spsq_raw_buf.size(), spsq, spsq_raw_buf.size(),
+ &num_out, (OVERLAPPED*)0)) {
+ err = GetLastError();
+ }
+
+ if (nvme_debugmode > 1)
+ pout(" [STORAGE_QUERY_PROPERTY: ReturnData=0x%08x, Reserved[3]={0x%x, 0x%x, 0x%x}]\n",
+ (unsigned)spsq->ProtocolSpecific.FixedProtocolReturnData,
+ (unsigned)spsq->ProtocolSpecific.Reserved[0],
+ (unsigned)spsq->ProtocolSpecific.Reserved[1],
+ (unsigned)spsq->ProtocolSpecific.Reserved[2]);
+
+ // NVMe status is checked by IOCTL
+ if (err)
+ return set_err(EIO, "IOCTL_STORAGE_QUERY_PROPERTY(NVMe) failed, Error=%ld", err);
+
+ if (in.direction() & nvme_cmd_in::data_in)
+ memcpy(in.buffer, spsq->DataBuffer, in.size);
+
+ out.result = spsq->ProtocolSpecific.FixedProtocolReturnData; // Completion DW0 ?
+ return true;
+}
+
+
/////////////////////////////////////////////////////////////////////////////
// win_smart_interface
// Platform specific interface
virtual std::string get_valid_custom_dev_types_str();
private:
- ata_device * get_usb_device(const char * name, int phydrive, int logdrive = -1);
+ smart_device * get_usb_device(const char * name, int phydrive, int logdrive = -1);
};
assert(vptr == vstr+strlen(vstr) && vptr+vlen+1 == vstr+sizeof(vstr));
// 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
+ // actual OS version. RtlGetVersion() is not affected.
LONG /*NTSTATUS*/ (WINAPI /*NTAPI*/ * RtlGetVersion_p)(LPOSVERSIONINFOEXW) =
(LONG (WINAPI *)(LPOSVERSIONINFOEXW))
GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlGetVersion");
}
const char * w = 0;
+ unsigned build = 0;
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" : "2016" ); break; // 10.0 = Win 10 : Win Server 2016 (TP only?)
+ switch ( (vi.dwMajorVersion << 4 | vi.dwMinorVersion) << 1
+ | (vi.wProductType > VER_NT_WORKSTATION ? 1 : 0) ) {
+ case 0x50<<1 :
+ case 0x50<<1 | 1: w = "2000"; break;
+ case 0x51<<1 : w = "xp"; break;
+ case 0x52<<1 : w = "xp64"; break;
+ case 0x52<<1 | 1: w = (!GetSystemMetrics(89/*SM_SERVERR2*/)
+ ? "2003"
+ : "2003r2"); break;
+ case 0x60<<1 : w = "vista"; break;
+ case 0x60<<1 | 1: w = "2008"; break;
+ case 0x61<<1 : w = "win7"; break;
+ case 0x61<<1 | 1: w = "2008r2"; break;
+ case 0x62<<1 : w = "win8"; break;
+ case 0x62<<1 | 1: w = "2012"; break;
+ case 0x63<<1 : w = "win8.1"; break;
+ case 0x63<<1 | 1: w = "2012r2"; break;
+ case 0xa0<<1 :
+ switch (vi.dwBuildNumber) {
+ case 10240: w = "w10-1507"; break;
+ case 10586: w = "w10-1511"; break;
+ case 14393: w = "w10-1607"; break;
+ case 15063: w = "w10-1703"; break;
+ case 16299: w = "w10-1709"; break;
+ case 17134: w = "w10-1803"; break;
+ case 17763: w = "w10-1809"; break;
+ default: w = "w10";
+ build = vi.dwBuildNumber; break;
+ } break;
+ case 0xa0<<1 | 1:
+ switch (vi.dwBuildNumber) {
+ case 14393: w = "2016"; break;
+ case 16299: w = "2016-1709"; break;
+ case 17134: w = "2016-1803"; break;
+ case 17763: w = "2019"; break;
+ default: w = (vi.dwBuildNumber < 17763
+ ? "2016"
+ : "2019");
+ build = vi.dwBuildNumber; break;
+ } break;
}
}
snprintf(vptr, vlen, "-%s%u.%u%s",
(vi.dwPlatformId==VER_PLATFORM_WIN32_NT ? "nt" : "??"),
(unsigned)vi.dwMajorVersion, (unsigned)vi.dwMinorVersion, w64);
+ else if (build)
+ snprintf(vptr, vlen, "-%s-b%u%s", w, build, w64);
else if (vi.wServicePackMinor)
- snprintf(vptr, vlen, "-%s%s-sp%u.%u", w, w64, vi.wServicePackMajor, vi.wServicePackMinor);
+ snprintf(vptr, vlen, "-%s-sp%u.%u%s", w, vi.wServicePackMajor, vi.wServicePackMinor, w64);
else if (vi.wServicePackMajor)
- snprintf(vptr, vlen, "-%s%s-sp%u", w, w64, vi.wServicePackMajor);
+ snprintf(vptr, vlen, "-%s-sp%u%s", w, vi.wServicePackMajor, w64);
else
snprintf(vptr, vlen, "-%s%s", w, w64);
return vstr;
nvme_device * win_smart_interface::get_nvme_device(const char * name, const char * type,
unsigned nsid)
{
- return new win_nvme_device(this, name, type, nsid);
+ if (str_starts_with(skipdev(name), "nvme"))
+ return new win_nvme_device(this, name, type, nsid);
+ return new win10_nvme_device(this, name, type, nsid);
}
// Return value for device detection functions
-enum win_dev_type { DEV_UNKNOWN = 0, DEV_ATA, DEV_SCSI, DEV_SAT, DEV_USB };
+enum win_dev_type { DEV_UNKNOWN = 0, DEV_ATA, DEV_SCSI, DEV_SAT, DEV_USB, DEV_NVME };
// Return true if ATA drive behind a SAT layer
static bool is_sat(const STORAGE_DEVICE_DESCRIPTOR_DATA * data)
case BusTypeUsb:
return DEV_USB;
+ case 0x11: // BusTypeNvme
+ return DEV_NVME;
+
+ case 0x12: //BusTypeSCM
+ case 0x13: //BusTypeUfs
+ case 0x14: //BusTypeMax,
default:
return DEV_UNKNOWN;
}
}
-ata_device * win_smart_interface::get_usb_device(const char * name,
+smart_device * win_smart_interface::get_usb_device(const char * name,
int phydrive, int logdrive /* = -1 */)
{
// Get USB bridge ID
return 0;
// Return SAT/USB device for this type
- return get_sat_device(usbtype, new win_scsi_device(this, name, ""));
+ return get_scsi_passthrough_device(usbtype, new win_scsi_device(this, name, ""));
}
smart_device * win_smart_interface::autodetect_smart_device(const char * name)
if (type == DEV_USB)
return get_usb_device(name, phydrive, logdrive);
+ if (type == DEV_NVME)
+ return new win10_nvme_device(this, name, "", 0 /* use default nsid */);
+
return 0;
}
}
}
- char name[20];
+ char name[32];
- if (ata || scsi || sat || usb) {
+ if (ata || scsi || sat || usb || nvme) {
// Scan up to 128 drives and 2 3ware controllers
const int max_raid = 2;
bool raid_seen[max_raid] = {false, false};
// Add physical drives
int len = strlen(name);
for (unsigned int pi = 0; pi < 32; pi++) {
- if (vers_ex.dwDeviceMapEx & (1L << pi)) {
+ if (vers_ex.dwDeviceMapEx & (1U << pi)) {
snprintf(name+len, sizeof(name)-1-len, ",%u", pi);
devlist.push_back( new win_ata_device(this, name, "ata") );
}
dev = new win_scsi_device(this, name, "");
break;
+ case DEV_NVME:
+ // STORAGE_QUERY_PROPERTY returned NVMe
+ if (!nvme)
+ continue;
+ dev = new win10_nvme_device(this, name, "", 0 /* use default nsid */);
+ break;
+
default:
// Unknown type
continue;
continue;
for (int pi = 0; pi < 32; pi++) {
- if (!(ports_used & (1 << pi)))
+ if (!(ports_used & (1U << 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;
}
-// 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;
-}
} // namespace