19#define _WIN32_WINNT WINVER
30#include "os_win32/wmiquery.h"
31#include "os_win32/popen.h"
64#define SELECT_WIN_32_64(x32, x64) (x32)
66#define SELECT_WIN_32_64(x32, x64) (x64)
71#if defined(__CYGWIN__) && !defined(stricmp)
72#define stricmp strcasecmp
73#define strnicmp strncasecmp
95#ifndef IOCTL_IDE_PASS_THROUGH
97#define IOCTL_IDE_PASS_THROUGH \
98 CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
132#ifndef FILE_DEVICE_SCSI
133#define FILE_DEVICE_SCSI 0x001b
136#ifndef IOCTL_SCSI_MINIPORT_SMART_VERSION
138#define IOCTL_SCSI_MINIPORT_SMART_VERSION ((FILE_DEVICE_SCSI << 16) + 0x0500)
139#define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501)
140#define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS ((FILE_DEVICE_SCSI << 16) + 0x0502)
141#define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS ((FILE_DEVICE_SCSI << 16) + 0x0503)
142#define IOCTL_SCSI_MINIPORT_ENABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0504)
143#define IOCTL_SCSI_MINIPORT_DISABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0505)
144#define IOCTL_SCSI_MINIPORT_RETURN_STATUS ((FILE_DEVICE_SCSI << 16) + 0x0506)
145#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE ((FILE_DEVICE_SCSI << 16) + 0x0507)
146#define IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES ((FILE_DEVICE_SCSI << 16) + 0x0508)
147#define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS ((FILE_DEVICE_SCSI << 16) + 0x0509)
148#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE ((FILE_DEVICE_SCSI << 16) + 0x050a)
149#define IOCTL_SCSI_MINIPORT_READ_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050b)
150#define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050c)
212#ifndef IOCTL_STORAGE_PROTOCOL_COMMAND
214#define IOCTL_STORAGE_PROTOCOL_COMMAND \
215 CTL_CODE(IOCTL_STORAGE_BASE, 0x04f0, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
219#ifndef STORAGE_PROTOCOL_STRUCTURE_VERSION
221#define STORAGE_PROTOCOL_STRUCTURE_VERSION 1
245#define STORAGE_PROTOCOL_COMMAND_FLAG_ADAPTER_REQUEST 0x80000000
246#define STORAGE_PROTOCOL_SPECIFIC_NVME_ADMIN_COMMAND 0x01
247#define STORAGE_PROTOCOL_COMMAND_LENGTH_NVME 0x40
257#ifndef NVME_NAMESPACE_ALL
270 ULONGLONG _unused[4];
291#define SMART_VENDOR_3WARE 0x13C1
325#ifndef NVME_PASS_THROUGH_SRB_IO_CODE
327#define NVME_SIG_STR "NvmeMini"
328#define NVME_STORPORT_DRIVER 0xe000
330#define NVME_PASS_THROUGH_SRB_IO_CODE \
331 CTL_CODE(NVME_STORPORT_DRIVER, 0x0800, METHOD_BUFFERED, FILE_ANY_ACCESS)
374#pragma warning(disable:4250)
380 pout(
"To continue, add one or more '-T permissive' options.\n");
392 return ( ((
'A' <=
s[0] &&
s[0] <=
'Z') || (
'a' <=
s[0] &&
s[0] <=
'z'))
394 && (!
s[2] || ( strchr(
"/\\\"",
s[2])
395 && (!
s[3] || (
s[3] ==
'.' && !
s[4]))) ) ?
396 (
s[0] & 0x1f) - 1 : -1);
408 int phydrive = xy[0] -
'a';
410 phydrive = (phydrive + 1) * (
'z' -
'a' + 1) + (xy[1] -
'a');
414static void copy_swapped(
unsigned char * dest,
const char * src,
int destsize)
416 int srclen = strcspn(src,
"\r\n");
418 for (i = 0; i < destsize-1 && i < srclen-1; i+=2) {
419 dest[i] = src[i+1]; dest[i+1] = src[i];
421 if (i < destsize-1 && i < srclen)
435 m_fh(INVALID_HANDLE_VALUE)
442 virtual bool close();
462 if (
m_fh != INVALID_HANDLE_VALUE)
468 return (
m_fh != INVALID_HANDLE_VALUE);
473 if (
m_fh == INVALID_HANDLE_VALUE)
475 BOOL rc = ::CloseHandle(
m_fh);
476 m_fh = INVALID_HANDLE_VALUE;
483#define SMART_CYL_LOW 0x4F
484#define SMART_CYL_HI 0xC2
488 pout(
"%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
489 (out?
"STS":
"CMD"), r->bCommandReg, (out?
"ERR":
" FR"), r->bFeaturesReg,
490 r->bSectorCountReg, r->bSectorNumberReg, r->bCylLowReg, r->bCylHighReg, r->bDriveHeadReg);
507 GETVERSIONINPARAMS vers; memset(&vers, 0,
sizeof(vers));
511 if (!DeviceIoControl(hdevice, SMART_GET_VERSION,
512 NULL, 0, &vers,
sizeof(vers), &num_out, NULL)) {
514 pout(
" SMART_GET_VERSION failed, Error=%u\n", (
unsigned)GetLastError());
518 assert(num_out ==
sizeof(GETVERSIONINPARAMS));
521 pout(
" SMART_GET_VERSION succeeded, bytes returned: %u\n"
522 " Vers = %d.%d, Caps = 0x%x, DeviceMap = 0x%02x\n",
523 (
unsigned)num_out, vers.bVersion, vers.bRevision,
524 (
unsigned)vers.fCapabilities, vers.bIDEDeviceMap);
526 pout(
" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08x\n",
531 *ata_version_ex = vers_ex;
540static int smart_ioctl(HANDLE hdevice, IDEREGS * regs,
char *
data,
unsigned datasize,
int port)
542 SENDCMDINPARAMS inpar;
545 unsigned char outbuf[
sizeof(SENDCMDOUTPARAMS)-1 + 512];
546 const SENDCMDOUTPARAMS * outpar;
548 unsigned int size_out;
551 memset(&inpar, 0,
sizeof(inpar));
552 inpar.irDriveRegs = *regs;
556 inpar.irDriveRegs.bDriveHeadReg |= 0xa0;
568 if (datasize == 512) {
569 code = SMART_RCV_DRIVE_DATA; name =
"SMART_RCV_DRIVE_DATA";
570 inpar.cBufferSize = size_out = 512;
572 else if (datasize == 0) {
573 code = SMART_SEND_DRIVE_COMMAND; name =
"SMART_SEND_DRIVE_COMMAND";
575 size_out =
sizeof(IDEREGS);
585 memset(&outbuf, 0,
sizeof(outbuf));
587 if (!DeviceIoControl(hdevice, code, &inpar,
sizeof(SENDCMDINPARAMS)-1,
588 outbuf,
sizeof(SENDCMDOUTPARAMS)-1 + size_out, &num_out, NULL)) {
590 long err = GetLastError();
592 pout(
" %s failed, Error=%ld\n", name, err);
595 errno = ( err == ERROR_INVALID_FUNCTION
596 || err == ERROR_INVALID_PARAMETER
597 || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
602 outpar = (
const SENDCMDOUTPARAMS *)outbuf;
604 if (outpar->DriverStatus.bDriverError) {
606 pout(
" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
607 outpar->DriverStatus.bDriverError, outpar->DriverStatus.bIDEError);
610 errno = (!outpar->DriverStatus.bIDEError ? ENOSYS : EIO);
615 pout(
" %s succeeded, bytes returned: %u (buffer %u)\n", name,
616 (
unsigned)num_out, (
unsigned)outpar->cBufferSize);
618 (
const IDEREGS *)(outpar->bBuffer) : NULL));
622 memcpy(
data, outpar->bBuffer, 512);
624 if (
nonempty(outpar->bBuffer,
sizeof(IDEREGS)))
625 memcpy(regs, outpar->bBuffer,
sizeof(IDEREGS));
628 pout(
" WARNING: driver does not return ATA registers in output buffer!\n");
629 *regs = inpar.irDriveRegs;
645 if (datasize > 512) {
652 const unsigned char magic = 0xcf;
665 buf,
size, buf,
size, &num_out, NULL)) {
666 long err = GetLastError();
668 pout(
" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err);
671 VirtualFree(buf, 0, MEM_RELEASE);
672 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
677 if (buf->
IdeReg.bCommandReg & 0x01) {
679 pout(
" IOCTL_IDE_PASS_THROUGH command failed:\n");
682 VirtualFree(buf, 0, MEM_RELEASE);
692 pout(
" IOCTL_IDE_PASS_THROUGH output data missing (%u, %u)\n",
696 VirtualFree(buf, 0, MEM_RELEASE);
704 pout(
" IOCTL_IDE_PASS_THROUGH succeeded, bytes returned: %u (buffer %u)\n",
711 VirtualFree(buf, 0, MEM_RELEASE);
730 const int max_sectors = 32;
733 ATA_PASS_THROUGH_EX apt;
735 UCHAR ucDataBuf[max_sectors * 512];
736 } ATA_PASS_THROUGH_EX_WITH_BUFFERS;
738 const unsigned char magic = 0xcf;
740 ATA_PASS_THROUGH_EX_WITH_BUFFERS ab; memset(&ab, 0,
sizeof(ab));
741 ab.apt.Length =
sizeof(ATA_PASS_THROUGH_EX);
745 ab.apt.TimeOutValue = 60;
746 unsigned size = offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS, ucDataBuf);
747 ab.apt.DataBufferOffset =
size;
750 if (datasize > (
int)
sizeof(ab.ucDataBuf)) {
754 ab.apt.AtaFlags = ATA_FLAGS_DATA_IN;
755 ab.apt.DataTransferLength = datasize;
757 ab.ucDataBuf[0] = magic;
759 else if (datasize < 0) {
760 if (-datasize > (
int)
sizeof(ab.ucDataBuf)) {
764 ab.apt.AtaFlags = ATA_FLAGS_DATA_OUT;
765 ab.apt.DataTransferLength = -datasize;
767 memcpy(ab.ucDataBuf,
data, -datasize);
770 assert(ab.apt.AtaFlags == 0);
771 assert(ab.apt.DataTransferLength == 0);
774 assert(
sizeof(ab.apt.CurrentTaskFile) ==
sizeof(IDEREGS));
775 IDEREGS * ctfregs = (IDEREGS *)ab.apt.CurrentTaskFile;
776 IDEREGS * ptfregs = (IDEREGS *)ab.apt.PreviousTaskFile;
780 *ptfregs = *prev_regs;
781 ab.apt.AtaFlags |= ATA_FLAGS_48BIT_COMMAND;
785 if (!DeviceIoControl(hdevice, IOCTL_ATA_PASS_THROUGH,
786 &ab,
size, &ab,
size, &num_out, NULL)) {
787 long err = GetLastError();
789 pout(
" IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err);
792 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
797 if (ctfregs->bCommandReg & (0x01|0x08)) {
799 pout(
" IOCTL_ATA_PASS_THROUGH command failed:\n");
809 || (ab.ucDataBuf[0] == magic && !
nonempty(ab.ucDataBuf+1, datasize-1))) {
811 pout(
" IOCTL_ATA_PASS_THROUGH output data missing (%u)\n", (
unsigned)num_out);
817 memcpy(
data, ab.ucDataBuf, datasize);
821 pout(
" IOCTL_ATA_PASS_THROUGH succeeded, bytes returned: %u\n", (
unsigned)num_out);
826 *prev_regs = *ptfregs;
843 DWORD code = 0;
const char * name = 0;
847 else if (regs->bCommandReg ==
ATA_SMART_CMD)
switch (regs->bFeaturesReg) {
881 SENDCMDOUTPARAMS out;
885 STATIC_ASSERT(
sizeof(sb) ==
sizeof(SRB_IO_CONTROL)+
sizeof(SENDCMDINPARAMS)-1+512);
886 memset(&sb, 0,
sizeof(sb));
890 if (datasize > (
int)
sizeof(sb.space)+1) {
896 else if (datasize < 0) {
897 if (-datasize > (
int)
sizeof(sb.space)+1) {
902 memcpy(sb.params.in.bBuffer,
data,
size);
905 size =
sizeof(IDEREGS);
908 sb.srbc.HeaderLength =
sizeof(SRB_IO_CONTROL);
909 memcpy(sb.srbc.Signature,
"SCSIDISK", 8);
910 sb.srbc.Timeout = 60;
911 sb.srbc.ControlCode = code;
913 sb.srbc.Length =
sizeof(SENDCMDINPARAMS)-1 +
size;
914 sb.params.in.irDriveRegs = *regs;
915 sb.params.in.cBufferSize =
size;
918 size +=
sizeof(SRB_IO_CONTROL) +
sizeof(SENDCMDINPARAMS)-1;
920 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
921 &sb,
size, &sb,
size, &num_out, NULL)) {
922 long err = GetLastError();
924 pout(
" IOCTL_SCSI_MINIPORT_%s failed, Error=%ld\n", name, err);
927 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
932 if (sb.srbc.ReturnCode) {
934 pout(
" IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08x\n", name, (
unsigned)sb.srbc.ReturnCode);
941 if (sb.params.out.DriverStatus.bDriverError) {
943 pout(
" IOCTL_SCSI_MINIPORT_%s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
944 sb.params.out.DriverStatus.bDriverError, sb.params.out.DriverStatus.bIDEError);
947 errno = (!sb.params.out.DriverStatus.bIDEError ? ENOSYS : EIO);
952 pout(
" IOCTL_SCSI_MINIPORT_%s succeeded, bytes returned: %u (buffer %u)\n", name,
953 (
unsigned)num_out, (
unsigned)sb.params.out.cBufferSize);
955 (
const IDEREGS *)(sb.params.out.bBuffer) : 0));
959 memcpy(
data, sb.params.out.bBuffer, datasize);
961 memcpy(regs, sb.params.out.bBuffer,
sizeof(IDEREGS));
977 STATIC_ASSERT(
sizeof(sb) ==
sizeof(SRB_IO_CONTROL)+
sizeof(IDEREGS)+512);
979 if (!(0 <= datasize && datasize <= (
int)
sizeof(sb.buffer) && port >= 0)) {
983 memset(&sb, 0,
sizeof(sb));
984 strncpy((
char *)sb.srbc.Signature,
"<3ware>",
sizeof(sb.srbc.Signature));
985 sb.srbc.HeaderLength =
sizeof(SRB_IO_CONTROL);
986 sb.srbc.Timeout = 60;
987 sb.srbc.ControlCode = 0xA0000000;
988 sb.srbc.ReturnCode = 0;
989 sb.srbc.Length =
sizeof(IDEREGS) + (datasize > 0 ? datasize : 1);
991 sb.regs.bReserved = port;
994 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
995 &sb,
sizeof(sb), &sb,
sizeof(sb), &num_out, NULL)) {
996 long err = GetLastError();
998 pout(
" ATA via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err);
1001 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
1005 if (sb.srbc.ReturnCode) {
1007 pout(
" ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (
unsigned)sb.srbc.ReturnCode);
1016 memcpy(
data, sb.buffer, datasize);
1019 pout(
" ATA via IOCTL_SCSI_MINIPORT succeeded, bytes returned: %u\n", (
unsigned)num_out);
1035 SRB_IO_CONTROL srbc;
1036 memset(&srbc, 0,
sizeof(srbc));
1037 strncpy((
char *)srbc.Signature,
"<3ware>",
sizeof(srbc.Signature));
1038 srbc.HeaderLength =
sizeof(SRB_IO_CONTROL);
1040 srbc.ControlCode = 0xCC010014;
1041 srbc.ReturnCode = 0;
1045 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
1046 &srbc,
sizeof(srbc), &srbc,
sizeof(srbc), &num_out, NULL)) {
1047 long err = GetLastError();
1049 pout(
" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err);
1050 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
1053 if (srbc.ReturnCode) {
1055 pout(
" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (
unsigned)srbc.ReturnCode);
1060 pout(
" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT succeeded\n");
1078 STORAGE_PROPERTY_QUERY query = {StorageDeviceProperty, PropertyStandardQuery, {0} };
1082 if (!DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY,
1083 &query,
sizeof(query),
data,
sizeof(*
data), &num_out, NULL)) {
1085 pout(
" IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%u\n", (
unsigned)GetLastError());
1091 pout(
" IOCTL_STORAGE_QUERY_PROPERTY returns:\n"
1093 " Product: \"%s\"\n"
1094 " Revision: \"%s\"\n"
1096 " BusType: 0x%02x\n",
1097 (
data->desc.VendorIdOffset ?
data->raw+
data->desc.VendorIdOffset :
"(null)"),
1098 (
data->desc.ProductIdOffset ?
data->raw+
data->desc.ProductIdOffset :
"(null)"),
1099 (
data->desc.ProductRevisionOffset ?
data->raw+
data->desc.ProductRevisionOffset :
"(null)"),
1100 (
data->desc.RemovableMedia?
"Yes":
"No"),
data->desc.BusType
1116 STORAGE_PREDICT_FAILURE
pred;
1120 if (!DeviceIoControl(hdevice, IOCTL_STORAGE_PREDICT_FAILURE,
1121 0, 0, &
pred,
sizeof(
pred), &num_out, NULL)) {
1123 pout(
" IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%u\n", (
unsigned)GetLastError());
1129 pout(
" IOCTL_STORAGE_PREDICT_FAILURE returns:\n"
1130 " PredictFailure: 0x%08x\n"
1131 " VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n",
1132 (
unsigned)
pred.PredictFailure,
1133 pred.VendorSpecific[0],
pred.VendorSpecific[1],
pred.VendorSpecific[2],
1134 pred.VendorSpecific[
sizeof(
pred.VendorSpecific)-1]
1138 memcpy(
data,
pred.VendorSpecific,
sizeof(
pred.VendorSpecific));
1139 return (!
pred.PredictFailure ? 0 : 1);
1150 memset(
id, 0,
sizeof(*
id));
1154 char model[
sizeof(
id->model) + 1] =
"";
1157 if (
data.desc.VendorIdOffset) {
1158 for ( ;i <
sizeof(model)-1 &&
data.raw[
data.desc.VendorIdOffset+i]; i++)
1159 model[i] =
data.raw[
data.desc.VendorIdOffset+i];
1162 if (
data.desc.ProductIdOffset) {
1164 while (i > 0 && model[i-1] ==
' ' && (i < 2 || model[i-2] ==
' '))
1167 if (i <= 4 && !memcmp(model,
"ATA", 3) && (i == 3 || model[3] ==
' '))
1169 for (
unsigned j = 0; i <
sizeof(model)-1 &&
data.raw[
data.desc.ProductIdOffset+j]; i++, j++)
1170 model[i] =
data.raw[
data.desc.ProductIdOffset+j];
1173 while (i > 0 && model[i-1] ==
' ')
1178 if (
data.desc.ProductRevisionOffset)
1181 id->command_set_1 = 0x0001;
id->command_set_2 = 0x4000;
1182 id->cfs_enable_1 = 0x0001;
id->csf_default = 0x4000;
1192 if (!ws.connect()) {
1194 pout(
"WMI connect failed\n");
1199 if (!ws.query1(wo,
"SELECT Model,SerialNumber FROM Win32_DiskDrive WHERE "
1200 "DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive))
1203 std::string serial = wo.get_str(
"SerialNumber");
1205 pout(
" WMI:PhysicalDrive%d: \"%s\", S/N:\"%s\"\n", drive, wo.get_str(
"Model").c_str(), serial.c_str());
1217 unsigned short & vendor_id,
1218 unsigned short & product_id)
1223 if (!ws.connect()) {
1225 pout(
"WMI connect failed\n");
1233 if (0 <= logdrive && logdrive <=
'Z'-
'A') {
1235 if (!ws.query1(wo,
"ASSOCIATORS OF {Win32_LogicalDisk.DeviceID=\"%c:\"} WHERE ResultClass = Win32_DiskPartition",
1239 std::string partid = wo.get_str(
"DeviceID");
1241 pout(
"%c: --> \"%s\" -->\n",
'A'+logdrive, partid.c_str());
1244 if (!ws.query1(wo,
"ASSOCIATORS OF {Win32_DiskPartition.DeviceID=\"%s\"} WHERE ResultClass = Win32_DiskDrive",
1248 name = wo.get_str(
"Model");
1250 pout(
"%s --> \"%s\":\n", wo.get_str(
"DeviceID").c_str(), name.c_str());
1253 else if (phydrive >= 0) {
1255 if (!ws.query1(wo,
"SELECT Model FROM Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", phydrive))
1258 name = wo.get_str(
"Model");
1260 pout(
"\\.\\\\PHYSICALDRIVE%d --> \"%s\":\n", phydrive, name.c_str());
1268 if (!ws.query(we,
"SELECT Antecedent,Dependent FROM Win32_USBControllerDevice"))
1271 unsigned short usb_venid = 0, prev_usb_venid = 0;
1272 unsigned short usb_proid = 0, prev_usb_proid = 0;
1273 std::string prev_usb_ant;
1274 std::string prev_ant, ant, dep;
1278 while (we.next(wo)) {
1281 ant = wo.get_str(
"Antecedent");
1282 dep = wo.get_str(
"Dependent");
1284 if (debug && ant != prev_ant)
1285 pout(
" %s:\n", ant.c_str());
1291 pout(
" | (\"%s\")\n", dep.c_str());
1295 std::string devid(dep.c_str()+
match[1].rm_so,
match[1].rm_eo-
match[1].rm_so);
1300 if (!(sscanf(devid.c_str(),
"USB\\\\VID_%4hx&PID_%4hx%n",
1301 &prev_usb_venid, &prev_usb_proid, &nc) == 2 && nc == 9+4+5+4)) {
1302 prev_usb_venid = prev_usb_proid = 0;
1306 pout(
" +-> \"%s\" [0x%04x:0x%04x]\n", devid.c_str(), prev_usb_venid, prev_usb_proid);
1311 pout(
" +--> \"%s\"\n", devid.c_str());
1315 if (!ws.query1(wo2,
"SELECT Name FROM Win32_PnPEntity WHERE DeviceID=\"%s\"", devid.c_str()))
1317 std::string name2 = wo2.get_str(
"Name");
1320 if (name2 != name) {
1322 pout(
" +---> (\"%s\")\n", name2.c_str());
1327 if (!(ant == prev_usb_ant && prev_usb_venid)) {
1329 pout(
" +---> \"%s\" (Error: No USB bridge found)\n", name2.c_str());
1336 if (!(usb_venid == prev_usb_venid && usb_proid == prev_usb_proid)) {
1338 pout(
" +---> \"%s\" (Error: More than one USB ID found)\n", name2.c_str());
1344 usb_venid = prev_usb_venid;
1345 usb_proid = prev_usb_proid;
1347 pout(
" +===> \"%s\" [0x%04x:0x%04x]\n", name2.c_str(), usb_venid, usb_proid);
1353 pout(
" | \"%s\"\n", devid.c_str());
1360 vendor_id = usb_venid;
1361 product_id = usb_proid;
1376 if (!GetDevicePowerState(hdevice, &state)) {
1377 long err = GetLastError();
1379 pout(
" GetDevicePowerState() failed, Error=%ld\n", err);
1380 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
1387 pout(
" GetDevicePowerState() succeeded, state=%d\n", state);
1404 virtual bool open()
override;
1413 bool open(
bool query_device);
1415 bool open(
int phydrive,
int logdrive,
const char * options,
int port,
bool query_device);
1430 m_usr_options(false),
1433 m_id_is_cached(false),
1464 char drive[2+1] =
"", options[8+1] =
"";
int n1 = -1, n2 = -1;
1465 if ( sscanf(name,
"%*[sh]d%2[a-z]%n:%6[saimfp]%n", drive, &n1, options, &n2) >= 1
1466 && ((n1 == len && !options[0]) || n2 == len) ) {
1470 drive[0] = 0; options[0] = 0; n1 = -1; n2 = -1;
1472 if ( sscanf(name,
"%*[sh]d%2[a-z],%u%n:%7[saimfp3]%n", drive, &port, &n1, options, &n2) >= 2
1473 && port < 32 && ((n1 == len && !options[0]) || n2 == len) ) {
1477 int phydrive = -1; port = ~0; n1 = -1; n2 = -1;
1478 if ( sscanf(name,
"pd%d%n,%u%n", &phydrive, &n1, &port, &n2) >= 1
1479 && phydrive >= 0 && ((n1 == len && (
int)port < 0) || (n2 == len && port < 32))) {
1480 return open(phydrive, -1,
"", (
int)port, query_device);
1484 if (logdrive >= 0) {
1485 return open(-1, logdrive,
"", -1, query_device);
1496 if (0 <= phydrive && phydrive <= 255)
1497 snprintf(devpath,
sizeof(devpath)-1,
"\\\\.\\PhysicalDrive%d", (
m_phydrive = phydrive));
1498 else if (0 <= logdrive && logdrive <=
'Z'-
'A')
1499 snprintf(devpath,
sizeof(devpath)-1,
"\\\\.\\%c:",
'A'+logdrive);
1504 HANDLE h = INVALID_HANDLE_VALUE;
1505 if (!(*options && !options[strspn(options,
"fp")]) && !query_device) {
1508 h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
1509 FILE_SHARE_READ|FILE_SHARE_WRITE,
1510 NULL, OPEN_EXISTING, 0, 0);
1512 if (h == INVALID_HANDLE_VALUE) {
1515 h = CreateFileA(devpath, 0,
1516 FILE_SHARE_READ|FILE_SHARE_WRITE,
1517 NULL, OPEN_EXISTING, 0, 0);
1519 if (h == INVALID_HANDLE_VALUE) {
1520 long err = GetLastError();
1521 if (err == ERROR_FILE_NOT_FOUND)
1522 set_err(ENOENT,
"%s: not found", devpath);
1523 else if (err == ERROR_ACCESS_DENIED)
1524 set_err(EACCES,
"%s: access denied", devpath);
1526 set_err(EIO,
"%s: Error=%ld", devpath, err);
1532 if (!
m_admin && !query_device) {
1533 static bool noadmin_warning =
false;
1534 if (!noadmin_warning) {
1535 pout(
"Warning: Limited functionality due to missing admin rights\n");
1536 noadmin_warning =
true;
1541 pout(
"%s: successfully opened%s\n", devpath, (!
m_admin ?
" (without admin rights)" :
""));
1569 unsigned portmap = 0;
1573 pout(
"SMART_GET_VERSION returns unknown Identifier = 0x%04x\n"
1574 "This is no 3ware 9000 controller or driver has no SMART support.\n",
1582 pout(
"%s: ATA driver has no SMART support\n", devpath);
1598 if (!(portmap & (1U << port))) {
1601 return set_err(ENOENT,
"%s: Port %d is empty or does not exist", devpath, port);
1645 return set_err(ENOSYS,
"SMART DISABLE requires 3ware port number");
1648 const char * valid_options = 0;
1660 valid_options =
"pai3";
1689 valid_options =
"a";
1713 if (!valid_options) {
1719 valid_options =
"a";
1722 valid_options =
"ai";
1727 if (strchr(valid_options,
'f'))
1728 valid_options =
"f";
1729 else if (strchr(valid_options,
'p'))
1730 valid_options =
"p";
1732 return set_err(ENOSYS,
"Function requires admin rights");
1736 IDEREGS regs, prev_regs;
1741 regs.bSectorNumberReg = lo.
lba_low;
1744 regs.bDriveHeadReg = lo.
device;
1745 regs.bCommandReg = lo.
command;
1750 prev_regs.bFeaturesReg = hi.
features;
1752 prev_regs.bSectorNumberReg = hi.
lba_low;
1753 prev_regs.bCylLowReg = hi.
lba_mid;
1754 prev_regs.bCylHighReg = hi.
lba_high;
1755 prev_regs.bDriveHeadReg = hi.
device;
1756 prev_regs.bCommandReg = hi.
command;
1757 prev_regs.bReserved = 0;
1767 datasize = (int)in.
size;
1771 datasize = -(int)in.
size;
1775 return set_err(EINVAL,
"win_ata_device::ata_pass_through: invalid direction=%d",
1781 bool powered_up =
false;
1782 bool out_regs_set =
false;
1783 bool id_is_cached =
false;
1784 const char * options =
m_options.c_str();
1786 for (
int i = 0; ; i++) {
1787 char opt = options[i];
1793 regs.bSectorCountReg = 0xff;
1794 out_regs_set =
true;
1800 if (!strchr(valid_options, opt))
1805 assert( datasize == 0 || datasize == 512
1806 || (datasize == -512 && strchr(
"am", opt))
1807 || (datasize > 512 && opt ==
'a'));
1814 rc = -1; errno = ENOSYS;
1823 rc = -1; errno = ENOSYS;
1837 id_is_cached = (
m_port < 0);
1841 id_is_cached = (
m_port < 0);
1847 out_regs_set =
true;
1851 out_regs_set =
true;
1859 id_is_cached =
true;
1883 errno = ENOSYS; rc = -1;
1886 errno = ENOSYS; rc = -1;
1891 out_regs_set =
true;
1899 regs.bSectorCountReg = 0x00;
1900 out_regs_set =
true;
1907 rc = -1; errno = ENOSYS;
1916 if (errno != ENOSYS)
1920 out_regs_set =
false;
1927 lo.
error = regs.bFeaturesReg;
1929 lo.
lba_low = regs.bSectorNumberReg;
1932 lo.
device = regs.bDriveHeadReg;
1933 lo.
status = regs.bCommandReg;
1937 hi.
lba_low = prev_regs.bSectorNumberReg;
1938 hi.
lba_mid = prev_regs.bCylLowReg;
1939 hi.
lba_high = prev_regs.bCylHighReg;
1988 virtual bool csmi_ioctl(
unsigned code, IOCTL_HEADER * csmi_buffer,
1989 unsigned csmi_bufsiz) = 0;
2027 for (
int pi = 0; i < (int)max_phy_drives; i++, pi++) {
2028 if (min_pi <= pi && pi <= max_pi)
2030 if (pi >= (
int)max_phy_drives)
2049 memset(&driver_info_buf, 0,
sizeof(driver_info_buf));
2050 if (!
csmi_ioctl(CC_CSMI_SAS_GET_DRIVER_INFO, &driver_info_buf.
IoctlHeader,
sizeof(driver_info_buf)))
2056 pout(
"CSMI_SAS_DRIVER_INFO:\n");
2057 pout(
" Name: \"%.81s\"\n", driver_info.
szName);
2064 memset(&phy_info_buf, 0,
sizeof(phy_info_buf));
2077 memset(&raid_info_buf, 0,
sizeof(raid_info_buf));
2079 memset(&raid_info_buf, 0,
sizeof(raid_info_buf));
2085 pout(
"CSMI_SAS_RAID_INFO:\n");
2106 if (!memcmp(driver_info.
szName,
"rcraid", 6+1)) {
2112 int number_of_ports;
2113 for (
int mode = 0; ; mode++) {
2117 number_of_ports = 0;
2132 default: port = i;
break;
2140 if (number_of_ports <= port)
2141 number_of_ports = port + 1;
2146 if (found || mode > 2)
2164 pout(
"Phy[%d] Port: %2d%s\n", i, port, (i >= first_guessed_index ?
" (*guessed*)" :
""));
2165 pout(
" Type: 0x%02x, 0x%02x\n",
id.bDeviceType, at.bDeviceType);
2166 pout(
" InitProto: 0x%02x, 0x%02x\n",
id.bInitiatorPortProtocol, at.bInitiatorPortProtocol);
2167 pout(
" TargetProto: 0x%02x, 0x%02x\n",
id.bTargetPortProtocol, at.bTargetPortProtocol);
2169 pout(
" PhyIdent: 0x%02x, 0x%02x\n",
id.bPhyIdentifier, at.bPhyIdentifier);
2170 pout(
" SignalClass: 0x%02x, 0x%02x\n",
id.bSignalClass, at.bSignalClass);
2171 pout(
" Restricted: 0x%02x, 0x%02x\n",
id.bRestricted, at.bRestricted);
2172 const unsigned char *
b =
id.bSASAddress;
2173 pout(
" SASAddress: %02x %02x %02x %02x %02x %02x %02x %02x, ",
2174 b[0],
b[1],
b[2],
b[3],
b[4],
b[5],
b[6],
b[7]);
2176 pout(
"%02x %02x %02x %02x %02x %02x %02x %02x\n",
2177 b[0],
b[1],
b[2],
b[3],
b[4],
b[5],
b[6],
b[7]);
2181 return number_of_ports;
2189 if (number_of_ports < 0)
2192 unsigned ports_used = 0;
2208 ports_used |= (1U << p);
2217 return set_err(EINVAL,
"Invalid port number %d", port);
2222 if (number_of_ports < 0)
2225 int port_index = p2i[port];
2226 if (port_index < 0) {
2227 if (port < number_of_ports)
2228 return set_err(ENOENT,
"Port %d is disabled", port);
2230 return set_err(ENOENT,
"Port %d does not exist (#ports: %d)", port,
2236 return set_err(ENOENT,
"No device on port %d", port);
2243 return set_err(ENOENT,
"No SATA device on port %d (protocol: %d)",
2291 sizeof(
pthru.bDestinationSASAddress));
2309 return set_err(EINVAL,
"csmi_ata_device::ata_pass_through: invalid direction=%d",
2315 unsigned char * fis =
pthru.bCommandFIS;
2377 const char * req_type);
2381 virtual bool open()
override;
2383 virtual bool close()
override;
2385 virtual bool is_open()
const override;
2390 virtual bool csmi_ioctl(
unsigned code, IOCTL_HEADER * csmi_buffer,
2391 unsigned csmi_bufsiz)
override;
2402 const char * req_type)
2404 m_fh(INVALID_HANDLE_VALUE), m_port(-1)
2410 if (
m_fh != INVALID_HANDLE_VALUE)
2416 return (
m_fh != INVALID_HANDLE_VALUE);
2421 if (
m_fh == INVALID_HANDLE_VALUE)
2423 BOOL rc = CloseHandle(
m_fh);
2424 m_fh = INVALID_HANDLE_VALUE;
2432 unsigned contr_no = ~0, port = ~0;
int nc = -1;
2434 if (!( sscanf(name,
"csmi%u,%u%n", &contr_no, &port, &nc) >= 0
2435 && nc == (
int)strlen(name) && contr_no <= 9 && port < 32) )
2440 snprintf(devpath,
sizeof(devpath)-1,
"\\\\.\\Scsi%u:", contr_no);
2442 HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
2443 FILE_SHARE_READ|FILE_SHARE_WRITE,
2444 (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, 0);
2446 if (h == INVALID_HANDLE_VALUE) {
2447 long err = GetLastError();
2448 if (err == ERROR_FILE_NOT_FOUND)
2449 set_err(ENOENT,
"%s: not found", devpath);
2450 else if (err == ERROR_ACCESS_DENIED)
2451 set_err(EACCES,
"%s: access denied", devpath);
2453 set_err(EIO,
"%s: Error=%ld", devpath, err);
2458 pout(
" %s: successfully opened\n", devpath);
2482 unsigned csmi_bufsiz)
2487 case CC_CSMI_SAS_GET_DRIVER_INFO:
2489 case CC_CSMI_SAS_GET_RAID_INFO:
2491 case CC_CSMI_SAS_GET_PHY_INFO:
2492 case CC_CSMI_SAS_STP_PASSTHRU:
2495 return set_err(ENOSYS,
"Unknown CSMI code=%u", code);
2499 csmi_buffer->HeaderLength =
sizeof(IOCTL_HEADER);
2500 strncpy((
char *)csmi_buffer->Signature, sig,
sizeof(csmi_buffer->Signature));
2502 csmi_buffer->ControlCode = code;
2503 csmi_buffer->ReturnCode = 0;
2504 csmi_buffer->Length = csmi_bufsiz -
sizeof(IOCTL_HEADER);
2508 if (!DeviceIoControl(
m_fh, IOCTL_SCSI_MINIPORT,
2509 csmi_buffer, csmi_bufsiz, csmi_buffer, csmi_bufsiz, &num_out, (OVERLAPPED*)0)) {
2510 long err = GetLastError();
2512 pout(
" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, Error=%ld\n", code, err);
2513 if ( err == ERROR_INVALID_FUNCTION
2514 || err == ERROR_NOT_SUPPORTED
2515 || err == ERROR_DEV_NOT_EXIST)
2516 return set_err(ENOSYS,
"CSMI is not supported (Error=%ld)", err);
2518 return set_err(EIO,
"CSMI(%u) failed with Error=%ld", code, err);
2522 if (csmi_buffer->ReturnCode) {
2524 pout(
" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, ReturnCode=%u\n",
2525 code, (
unsigned)csmi_buffer->ReturnCode);
2527 return set_err(EIO,
"CSMI(%u) failed with ReturnCode=%u", code, (
unsigned)csmi_buffer->ReturnCode);
2531 pout(
" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) succeeded, bytes returned: %u\n", code, (
unsigned)num_out);
2550 virtual bool is_open()
const override;
2552 virtual bool open()
override;
2554 virtual bool close()
override;
2570 m_ident_valid(false), m_smart_valid(false)
2587 if (!OpenClipboard(NULL))
2589 HANDLE h = GetClipboardData(CF_TEXT);
2594 const void * p = GlobalLock(h);
2595 int n = GlobalSize(h);
2605static const char *
findstr(
const char * str,
const char * sub)
2607 const char *
s = strstr(str, sub);
2608 return (
s ?
s+strlen(sub) :
"");
2618 int size = -1, n1 = -1, n2 = -1;
2619 if (!strcmp(name,
"tw_cli/clip")) {
2622 else if (!strcmp(name,
"tw_cli/stdin")) {
2625 else if (sscanf(name,
"tw_cli/%nc%*u/p%*u%n", &n1, &n2) >= 0 && n2 == (
int)strlen(name)) {
2628 snprintf(
cmd,
sizeof(
cmd),
"tw_cli /%s show all", name+n1);
2630 pout(
"%s: Run: \"%s\"\n", name,
cmd);
2631 FILE * f = popen(
cmd,
"rb");
2642 pout(
"%s: Read %d bytes\n", name,
size);
2655 memset(
id, 0,
sizeof(*
id));
2659 unsigned long nblocks = 0;
2660 sscanf(
findstr(
buffer,
"Capacity = "),
"%*[^(\r\n](%lu", &nblocks);
2662 id->words047_079[49-47] = 0x0200;
2663 id->words047_079[60-47] = (
unsigned short)(nblocks );
2664 id->words047_079[61-47] = (
unsigned short)(nblocks>>16);
2666 id->command_set_1 = 0x0001;
id->command_set_2 = 0x4000;
2667 id->cfs_enable_1 = 0x0001;
id->csf_default = 0x4000;
2676 const char * s1 =
findstr(
s,
"<td class");
2679 s += strcspn(
s,
"\r\n");
2684 unsigned char * sd = (
unsigned char *)&
m_smart_buf;
2687 unsigned x = ~0;
int n = -1;
2688 if (!(sscanf(
s,
"%x %n", &x, &n) == 1 && !(x & ~0xff)))
2690 sd[i] = (
unsigned char)x;
2691 if (!(++i < 512 && n > 0))
2695 s += strcspn(
s,
"\r\n");
2698 if (!
id->model[1]) {
2700 char * err = strstr(
buffer,
"Error:");
2702 err = strstr(
buffer,
"error :");
2703 if (err && (err = strchr(err,
':'))) {
2706 err[strcspn(err,
"\r\n")] = 0;
2707 return set_err(EIO,
"%s", err);
2764 virtual bool open()
override;
2769 bool open(
int pd_num,
int ld_num,
int tape_num,
int sub_addr);
2776 const char * dev_name,
const char * req_type)
2785 char drive[2+1] =
"";
int sub_addr = -1;
int n1 = -1;
int n2 = -1;
2786 if ( sscanf(name,
"sd%2[a-z]%n,%d%n", drive, &n1, &sub_addr, &n2) >= 1
2787 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0)) ) {
2791 int pd_num = -1; sub_addr = -1; n1 = -1; n2 = -1;
2792 if ( sscanf(name,
"pd%d%n,%d%n", &pd_num, &n1, &sub_addr, &n2) >= 1
2793 && pd_num >= 0 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0))) {
2794 return open(pd_num, -1, -1, sub_addr);
2798 if (logdrive >= 0) {
2799 return open(-1, logdrive, -1, -1);
2802 int tape_num = -1; n1 = -1;
2803 if (sscanf(name,
"st%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
2804 return open(-1, -1, tape_num, -1);
2806 tape_num = -1; n1 = -1;
2807 if (sscanf(name,
"nst%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
2808 return open(-1, -1, tape_num, -1);
2811 tape_num = -1; n1 = -1;
2812 if (sscanf(name,
"tape%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
2813 return open(-1, -1, tape_num, -1);
2822 b[
sizeof(
b) - 1] =
'\0';
2824 snprintf(
b,
sizeof(
b) - 1,
"\\\\.\\PhysicalDrive%d", pd_num);
2825 else if (ld_num >= 0)
2826 snprintf(
b,
sizeof(
b) - 1,
"\\\\.\\%c:",
'A' + ld_num);
2827 else if (tape_num >= 0)
2828 snprintf(
b,
sizeof(
b) - 1,
"\\\\.\\TAPE%d", tape_num);
2835 HANDLE h = CreateFileA(
b, GENERIC_READ|GENERIC_WRITE,
2836 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
2837 OPEN_EXISTING, 0, 0);
2838 if (h == INVALID_HANDLE_VALUE) {
2839 set_err(ENODEV,
"%s: Open failed, Error=%u",
b, (
unsigned)GetLastError());
2850 UCHAR ucSenseBuf[64];
2859 struct SCSI_PASS_THROUGH_WITH_BUFFERS {
2860 SCSI_PASS_THROUGH spt;
2863 UCHAR ucDataBuf[512];
2866 SCSI_PASS_THROUGH_WITH_BUFFERS sb;
2867 memset(&sb, 0,
sizeof(sb));
2870 if (!( sbd->
spt.DataIn == SCSI_IOCTL_DATA_IN
2871 && sbd->
spt.DataTransferLength <=
sizeof(sb.ucDataBuf)))
2872 return ERROR_INVALID_PARAMETER;
2874 sb.spt.Length =
sizeof(sb.spt);
2875 sb.spt.CdbLength = sbd->
spt.CdbLength;
2876 memcpy(sb.spt.Cdb, sbd->
spt.Cdb,
sizeof(sb.spt.Cdb));
2877 sb.spt.SenseInfoLength =
sizeof(sb.ucSenseBuf);
2878 sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
2879 sb.spt.DataIn = sbd->
spt.DataIn;
2880 sb.spt.DataTransferLength = sbd->
spt.DataTransferLength;
2881 sb.spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf);
2882 sb.spt.TimeOutValue = sbd->
spt.TimeOutValue;
2885 if (!DeviceIoControl(h, IOCTL_SCSI_PASS_THROUGH,
2886 &sb,
sizeof(sb), &sb,
sizeof(sb), &num_out, 0))
2887 return GetLastError();
2889 sbd->
spt.ScsiStatus = sb.spt.ScsiStatus;
2893 sbd->
spt.DataTransferLength = sb.spt.DataTransferLength;
2894 if (sbd->
spt.DataIn == SCSI_IOCTL_DATA_IN && sb.spt.DataTransferLength > 0)
2895 memcpy(sbd->
spt.DataBuffer, sb.ucDataBuf, sb.spt.DataTransferLength);
2907 const unsigned char * ucp = iop->
cmnd;
2910 const int sz = (int)
sizeof(buff);
2913 j = snprintf(buff, sz,
" [%s: ", np ? np :
"<unknown opcode>");
2914 for (k = 0; k < (int)iop->
cmnd_len; ++k)
2915 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0),
"%02x ", ucp[k]);
2918 int trunc = (iop->
dxfer_len > 256) ? 1 : 0;
2920 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0),
"]\n Outgoing "
2921 "data, len=%d%s:\n", (
int)iop->
dxfer_len,
2922 (trunc ?
" [only first 256 bytes shown]" :
""));
2926 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0),
"]\n");
2932 set_err(EINVAL,
"cmnd_len too large");
2936 memset(&sb, 0,
sizeof(sb));
2937 sb.
spt.Length =
sizeof(SCSI_PASS_THROUGH_DIRECT);
2941 sb.
spt.SenseInfoOffset =
2948 sb.
spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
2951 sb.
spt.DataIn = SCSI_IOCTL_DATA_IN;
2956 if (sb.
spt.DataTransferLength == 1)
2960 sb.
spt.DataIn = SCSI_IOCTL_DATA_OUT;
2965 set_err(EINVAL,
"bad dxfer_dir");
2972 if (!DeviceIoControl(
get_fh(), IOCTL_SCSI_PASS_THROUGH_DIRECT,
2973 &sb,
sizeof(sb), &sb,
sizeof(sb), &num_out, 0))
2974 err = GetLastError();
2980 return set_err((err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO),
2981 "IOCTL_SCSI_PASS_THROUGH%s failed, Error=%ld",
2982 (direct ?
"_DIRECT" :
""), err);
2996 pout(
" >>> Sense buffer, len=%d:\n", slen);
2999 if ((iop->
sensep[0] & 0x7f) > 0x71)
3000 pout(
" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3004 pout(
" status=%x: sense_key=%x asc=%x ascq=%x\n",
3017 int trunc = (iop->
dxfer_len > 256) ? 1 : 0;
3019 (trunc ?
" [only first 256 bytes shown]" :
""));
3036 const unsigned char * ucp = iop->
cmnd;
3039 const int sz = (int)
sizeof(buff);
3042 j = snprintf(buff, sz,
" [%s: ", np ? np :
"<unknown opcode>");
3043 for (k = 0; k < (int)iop->
cmnd_len; ++k)
3044 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0),
"%02x ", ucp[k]);
3047 int trunc = (iop->
dxfer_len > 256) ? 1 : 0;
3049 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0),
"]\n Outgoing "
3050 "data, len=%d%s:\n", (
int)iop->
dxfer_len,
3051 (trunc ?
" [only first 256 bytes shown]" :
""));
3055 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0),
"]\n");
3064 memset(&sb, 0,
sizeof(sb));
3065 sb.
spt.Length =
sizeof(SCSI_PASS_THROUGH_DIRECT);
3067 sb.
spt.TargetId = targetid;
3072 sb.
spt.SenseInfoOffset =
3079 sb.
spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
3082 sb.
spt.DataIn = SCSI_IOCTL_DATA_IN;
3087 if (sb.
spt.DataTransferLength == 1)
3091 sb.
spt.DataIn = SCSI_IOCTL_DATA_OUT;
3102 if (!DeviceIoControl(fd, IOCTL_SCSI_PASS_THROUGH_DIRECT,
3103 &sb,
sizeof(sb), &sb,
sizeof(sb), &num_out, 0))
3104 err = GetLastError();
3126 pout(
" >>> Sense buffer, len=%d:\n", slen);
3129 if ((iop->
sensep[0] & 0x7f) > 0x71)
3130 pout(
" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3134 pout(
" status=%x: sense_key=%x asc=%x ascq=%x\n",
3147 int trunc = (iop->
dxfer_len > 256) ? 1 : 0;
3149 (trunc ?
" [only first 256 bytes shown]" :
""));
3167 virtual bool open()
override;
3183 set_fh(INVALID_HANDLE_VALUE);
3198 GENERIC_READ|GENERIC_WRITE,
3199 FILE_SHARE_READ|FILE_SHARE_WRITE,
3204 if(hFh == INVALID_HANDLE_VALUE)
3220 int ioctlreturn = 0;
3238#define SYNCOBJNAME "Global\\SynIoctlMutex"
3242 if (sscanf(
get_dev_name(),
"\\\\.\\scsi%d:", &ctlrnum) < 1)
3243 return set_err(EINVAL,
"unable to parse device name");
3245 snprintf(mutexstr,
sizeof(mutexstr),
"%s%d",
SYNCOBJNAME, ctlrnum);
3246 m_mutex = CreateMutex(NULL, FALSE, mutexstr);
3249 return set_err(EIO,
"CreateMutex failed");
3253 WaitForSingleObject(
m_mutex, INFINITE);
3281 virtual bool open()
override;
3297 set_fh(INVALID_HANDLE_VALUE);
3312 GENERIC_READ|GENERIC_WRITE,
3313 FILE_SHARE_READ|FILE_SHARE_WRITE,
3318 if(hFh == INVALID_HANDLE_VALUE)
3354 int ioctlreturn = 0;
3372#define SYNCOBJNAME "Global\\SynIoctlMutex"
3376 if (sscanf(
get_dev_name(),
"\\\\.\\scsi%d:", &ctlrnum) < 1)
3377 return set_err(EINVAL,
"unable to parse device name");
3379 snprintf(mutexstr,
sizeof(mutexstr),
"%s%d",
SYNCOBJNAME, ctlrnum);
3380 m_mutex = CreateMutex(NULL, FALSE, mutexstr);
3383 return set_err(EIO,
"CreateMutex failed");
3387 WaitForSingleObject(
m_mutex, INFINITE);
3418 virtual bool open()
override;
3437 const char *dev_name,
unsigned ctrnum,
unsigned target,
unsigned lun)
3439 m_ctrnum(ctrnum), m_lun(
lun), m_target(target)
3455 GENERIC_READ|GENERIC_WRITE,
3456 FILE_SHARE_READ|FILE_SHARE_WRITE,
3461 if (hFh == INVALID_HANDLE_VALUE)
3462 return set_err(ENODEV,
"Open failed, Error=%u", (
unsigned)GetLastError());
3474 const unsigned char * ucp = iop->
cmnd;
3477 const int sz = (int)
sizeof(buff);
3479 j = snprintf(buff, sz,
" [%s: ", np ? np :
"<unknown opcode>");
3480 for (k = 0; k < (int)iop->
cmnd_len; ++k)
3481 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0),
"%02x ", ucp[k]);
3484 int trunc = (iop->
dxfer_len > 256) ? 1 : 0;
3486 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0),
"]\n Outgoing "
3487 "data, len=%d%s:\n", (
int)iop->
dxfer_len,
3488 (trunc ?
" [only first 256 bytes shown]" :
""));
3492 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0),
"]\n");
3493 pout(
"buff %s\n",buff);
3497 constexpr unsigned scsiRequestBlockSize =
sizeof(SCSI_REQUEST_BLOCK);
3498 constexpr unsigned dataOffset = (
sizeof(SRB_IO_CONTROL) + scsiRequestBlockSize + 7) & 0xfffffff8;
3501 char * ioBuffer =
reinterpret_cast<char *
>(pthru_raw_buf.
data());
3502 SRB_IO_CONTROL * pSrbIO = (SRB_IO_CONTROL *) ioBuffer;
3503 SCSI_REQUEST_BLOCK * pScsiIO = (SCSI_REQUEST_BLOCK *) (ioBuffer +
sizeof(SRB_IO_CONTROL));
3504 char *pRequestSenseIO = (
char *) (ioBuffer +
sizeof(SRB_IO_CONTROL) + scsiRequestBlockSize);
3505 char *pDataIO = (
char *) (ioBuffer + dataOffset);
3506 memset(pScsiIO, 0, scsiRequestBlockSize);
3507 pScsiIO->Length = (USHORT) scsiRequestBlockSize;
3509 pScsiIO->PathId = 0;
3511 pScsiIO->Lun =
m_lun;
3512 pScsiIO->CdbLength = (int)iop->
cmnd_len;
3524 pout(
"aacraid: bad dxfer_dir\n");
3525 return set_err(EINVAL,
"aacraid: bad dxfer_dir\n");
3527 pScsiIO->DataTransferLength = (ULONG)iop->
dxfer_len;
3528 pScsiIO->TimeOutValue = iop->
timeout;
3529 UCHAR *pCdb = (UCHAR *) pScsiIO->Cdb;
3530 memcpy(pCdb, iop->
cmnd, 16);
3534 if (pScsiIO->SrbFlags & SRB_FLAGS_DATA_OUT){
3537 else if (pScsiIO->SrbFlags & SRB_FLAGS_DATA_IN){
3541 DWORD bytesReturned = 0;
3542 memset(pSrbIO, 0,
sizeof(SRB_IO_CONTROL));
3543 pSrbIO->HeaderLength =
sizeof(SRB_IO_CONTROL);
3544 memcpy(pSrbIO->Signature,
"AACAPI", 7);
3545 pSrbIO->ControlCode = ARCIOCTL_SEND_RAW_SRB;
3546 pSrbIO->Length = (dataOffset + iop->
dxfer_len -
sizeof(SRB_IO_CONTROL) + 7) & 0xfffffff8;
3547 pSrbIO->Timeout = 3*60;
3549 if (!DeviceIoControl(
3551 IOCTL_SCSI_MINIPORT,
3553 sizeof(SRB_IO_CONTROL) + pSrbIO->Length,
3555 sizeof(SRB_IO_CONTROL) + pSrbIO->Length,
3559 return set_err(EIO,
"ARCIOCTL_SEND_RAW_SRB failed, Error=%u", (
unsigned)GetLastError());
3564 int slen =
sizeof(pRequestSenseIO) + 8;
3565 if (slen > (
int)
sizeof(pRequestSenseIO))
3566 slen =
sizeof(pRequestSenseIO);
3569 memcpy(iop->
sensep, pRequestSenseIO, slen);
3573 pout(
" >>> Sense buffer, len=%d:\n", slen);
3576 if ((iop->
sensep[0] & 0x7f) > 0x71)
3577 pout(
" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3581 pout(
" status=%x: sense_key=%x asc=%x ascq=%x\n",
3594 int trunc = (iop->
dxfer_len > 256) ? 1 : 0;
3596 (trunc ?
" [only first 256 bytes shown]" :
""));
3597 dStrHex((
const uint8_t *)pDataIO, (trunc ? 256 : (
int)(iop->
dxfer_len)) , 1);
3612 const char * req_type,
unsigned nsid);
3614 virtual bool open()
override;
3630 const char * req_type,
unsigned nsid)
3641 snprintf(devpath,
sizeof(devpath)-1,
"\\\\.\\Scsi%d:", n);
3643 HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
3644 FILE_SHARE_READ|FILE_SHARE_WRITE,
3645 (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, 0);
3647 if (h == INVALID_HANDLE_VALUE) {
3648 long err = GetLastError();
3650 pout(
" %s: Open failed, Error=%ld\n", devpath, err);
3651 if (err == ERROR_FILE_NOT_FOUND)
3652 set_err(ENOENT,
"%s: not found", devpath);
3653 else if (err == ERROR_ACCESS_DENIED)
3654 set_err(EACCES,
"%s: access denied", devpath);
3656 set_err(EIO,
"%s: Error=%ld", devpath, err);
3661 pout(
" %s: successfully opened\n", devpath);
3693 char s[2+1] =
"";
int n1 = -1, n2 = -1, len = strlen(name);
3694 unsigned no = ~0,
nsid = 0xffffffff;
3695 sscanf(name,
"nvm%2[es]%u%nn%u%n",
s, &no, &n1, &
nsid, &n2);
3697 if (!( (n1 == len || (n2 == len &&
nsid > 0))
3698 &&
s[0] ==
'e' && (!
s[1] ||
s[1] ==
's') ))
3703 unsigned nvme_cnt = 0;
3704 for (
int i = 0; i < 32; i++) {
3712 if (nvme_cnt == no) {
3752 pthru->SrbIoCtrl.HeaderLength =
sizeof(SRB_IO_CONTROL);
3754 pthru->SrbIoCtrl.Timeout = 60;
3756 pthru->SrbIoCtrl.ReturnCode = 0;
3757 pthru->SrbIoCtrl.Length = pthru_raw_buf.
size() -
sizeof(SRB_IO_CONTROL);
3776 pthru->ReturnBufferLen = pthru_raw_buf.
size();
3780 BOOL ok = DeviceIoControl(
get_fh(), IOCTL_SCSI_MINIPORT,
3782 &num_out, (OVERLAPPED*)0);
3785 unsigned status =
pthru->CplEntry[3] >> 17;
3790 return set_err(EIO,
"NVME_PASS_THROUGH failed, Error=%u", (
unsigned)GetLastError());
3809 const char * req_type,
unsigned nsid);
3811 virtual bool open()
override;
3816 bool open(
int phydrive,
int logdrive);
3827 const char * req_type,
unsigned nsid)
3838 char drive[2 + 1] =
"";
int n = -1;
3839 if (sscanf(name,
"sd%2[a-z]%n", drive, &n) == 1 && n == len)
3843 int phydrive = -1; n = -1;
3844 if (sscanf(name,
"pd%d%n", &phydrive, &n) == 1 && phydrive >= 0 && n == len)
3845 return open(phydrive, -1);
3850 return open(-1, logdrive);
3860 snprintf(devpath,
sizeof(devpath),
"\\\\.\\PhysicalDrive%d", phydrive);
3862 snprintf(devpath,
sizeof(devpath),
"\\\\.\\%c:",
'A'+logdrive);
3865 HANDLE h = CreateFileA(devpath, GENERIC_READ | GENERIC_WRITE,
3866 FILE_SHARE_READ | FILE_SHARE_WRITE,
3867 (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, (HANDLE)0);
3868 if (h == INVALID_HANDLE_VALUE) {
3871 h = CreateFileA(devpath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
3872 (SECURITY_ATTRIBUTES*)0, OPEN_EXISTING, 0, (HANDLE)0);
3875 if (h == INVALID_HANDLE_VALUE) {
3876 long err = GetLastError();
3878 pout(
" %s: Open failed, Error=%ld\n", devpath, err);
3879 if (err == ERROR_FILE_NOT_FOUND)
3880 set_err(ENOENT,
"%s: not found", devpath);
3881 else if (err == ERROR_ACCESS_DENIED)
3882 set_err(EACCES,
"%s: access denied", devpath);
3884 set_err(EIO,
"%s: Error=%ld", devpath, err);
3889 pout(
" %s: successfully opened%s\n", devpath, (!admin ?
" (without admin rights)" :
""));
3941 return set_err(ENOSYS,
"NVMe admin command 0x%02x not supported", in.
opcode);
3951 pout(
" [STORAGE_QUERY_PROPERTY: Id=%u, Type=%u, Value=0x%08x, SubVal=0x%08x]\n",
3960 if (!DeviceIoControl(
get_fh(), IOCTL_STORAGE_QUERY_PROPERTY,
3961 spsq, spsq_raw_buf.
size(), spsq, spsq_raw_buf.
size(),
3962 &num_out, (OVERLAPPED*)0)) {
3963 err = GetLastError();
3967 pout(
" [STORAGE_QUERY_PROPERTY: ReturnData=0x%08x, Reserved[3]={0x%x, 0x%x, 0x%x}]\n",
3975 return set_err(EIO,
"IOCTL_STORAGE_QUERY_PROPERTY(NVMe) failed, Error=%ld", err);
3991 return set_err(ENOSYS,
"NVMe admin command 0x%02x not supported", in.
opcode);
4015 pout(
" [IOCTL_STORAGE_PROTOCOL_COMMAND(NVMe): CDW0.OPC=0x%02x, NSID=0x%04x, CDW10=0x%04x]\n",
4017 (
unsigned)nvcm->
NSID,
4024 spcm,
sizeof(spcm_buf), spcm,
sizeof(spcm_buf),
4025 &num_out, (OVERLAPPED*)0)) {
4026 err = GetLastError();
4031 return set_err(EIO,
"IOCTL_STORAGE_PROTOCOL_COMMAND(NVMe) failed, Error=%ld", err);
4040 return set_err(ENOSYS,
"Nonzero NVMe command dwords 11-15 not supported");
4067 const char * pattern = 0)
override;
4093 BOOL (WINAPI * IsWow64Process_p)(HANDLE, PBOOL) =
4094 (BOOL (WINAPI *)(HANDLE, PBOOL))(
void *)
4095 GetProcAddress(GetModuleHandleA(
"kernel32.dll"),
"IsWow64Process");
4096 if (!IsWow64Process_p)
4099 if (!IsWow64Process_p(GetCurrentProcess(), &w64))
4108 char vstr[
sizeof(SMARTMONTOOLS_BUILD_HOST)-1+
sizeof(
"-2003r2(64)-sp2.1")+13]
4109 = SMARTMONTOOLS_BUILD_HOST;
4112 char *
const vptr = vstr+
sizeof(SMARTMONTOOLS_BUILD_HOST)-1;
4113 const int vlen =
sizeof(vstr)-
sizeof(SMARTMONTOOLS_BUILD_HOST);
4114 assert(vptr == vstr+strlen(vstr) && vptr+vlen+1 == vstr+
sizeof(vstr));
4118 LONG (WINAPI * RtlGetVersion_p)(LPOSVERSIONINFOEXW) =
4119 (LONG (WINAPI *)(LPOSVERSIONINFOEXW))(
void *)
4120 GetProcAddress(GetModuleHandleA(
"ntdll.dll"),
"RtlGetVersion");
4122 OSVERSIONINFOEXW vi; memset(&vi, 0,
sizeof(vi));
4123 vi.dwOSVersionInfoSize =
sizeof(vi);
4124 if (!RtlGetVersion_p || RtlGetVersion_p(&vi)) {
4125 if (!GetVersionExW((OSVERSIONINFOW *)&vi))
4131 if ( vi.dwPlatformId == VER_PLATFORM_WIN32_NT
4132 && vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) {
4133 switch ( (vi.dwMajorVersion << 4 | vi.dwMinorVersion) << 1
4134 | (vi.wProductType > VER_NT_WORKSTATION ? 1 : 0) ) {
4136 case 0x50<<1 | 1:
w =
"2000";
break;
4137 case 0x51<<1 :
w =
"xp";
break;
4138 case 0x52<<1 :
w =
"xp64";
break;
4139 case 0x52<<1 | 1:
w = (!GetSystemMetrics(89)
4142 case 0x60<<1 :
w =
"vista";
break;
4143 case 0x60<<1 | 1:
w =
"2008";
break;
4144 case 0x61<<1 :
w =
"win7";
break;
4145 case 0x61<<1 | 1:
w =
"2008r2";
break;
4146 case 0x62<<1 :
w =
"win8";
break;
4147 case 0x62<<1 | 1:
w =
"2012";
break;
4148 case 0x63<<1 :
w =
"win8.1";
break;
4149 case 0x63<<1 | 1:
w =
"2012r2";
break;
4151 switch (vi.dwBuildNumber) {
4152 case 10240:
w =
"w10-1507";
break;
4153 case 10586:
w =
"w10-1511";
break;
4154 case 14393:
w =
"w10-1607";
break;
4155 case 15063:
w =
"w10-1703";
break;
4156 case 16299:
w =
"w10-1709";
break;
4157 case 17134:
w =
"w10-1803";
break;
4158 case 17763:
w =
"w10-1809";
break;
4159 case 18362:
w =
"w10-1903";
break;
4160 case 18363:
w =
"w10-1909";
break;
4161 case 19041:
w =
"w10-2004";
break;
4162 case 19042:
w =
"w10-20H2";
break;
4163 case 19043:
w =
"w10-21H1";
break;
4164 case 19044:
w =
"w10-21H2";
break;
4165 case 19045:
w =
"w10-22H2";
break;
4166 case 22000:
w =
"w11-21H2";
break;
4167 case 22621:
w =
"w11-22H2";
break;
4168 case 22631:
w =
"w11-23H2";
break;
4169 case 26100:
w =
"w11-24H2";
break;
4170 default:
w = (vi.dwBuildNumber < 22000
4173 build = vi.dwBuildNumber;
break;
4176 switch (vi.dwBuildNumber) {
4177 case 14393:
w =
"2016-1607";
break;
4178 case 16299:
w =
"2016-1709";
break;
4179 case 17134:
w =
"2016-1803";
break;
4180 case 17763:
w =
"2019-1809";
break;
4181 case 18362:
w =
"2019-1903";
break;
4182 case 18363:
w =
"2019-1909";
break;
4183 case 19041:
w =
"2019-2004";
break;
4184 case 19042:
w =
"2019-20H2";
break;
4185 case 20348:
w =
"2022-21H2";
break;
4186 case 26100:
w =
"2025-24H2";
break;
4187 default:
w = (vi.dwBuildNumber < 17763
4189 : vi.dwBuildNumber < 20348
4191 : vi.dwBuildNumber < 26100
4194 build = vi.dwBuildNumber;
break;
4199 const char * w64 =
"";
4206 snprintf(vptr, vlen,
"-%s%u.%u%s",
4207 (vi.dwPlatformId==VER_PLATFORM_WIN32_NT ?
"nt" :
"??"),
4208 (
unsigned)vi.dwMajorVersion, (
unsigned)vi.dwMinorVersion, w64);
4210 snprintf(vptr, vlen,
"-%s-b%u%s",
w, build, w64);
4211 else if (vi.wServicePackMinor)
4212 snprintf(vptr, vlen,
"-%s-sp%u.%u%s",
w, vi.wServicePackMajor, vi.wServicePackMinor, w64);
4213 else if (vi.wServicePackMajor)
4214 snprintf(vptr, vlen,
"-%s-sp%u%s",
w, vi.wServicePackMajor, w64);
4216 snprintf(vptr, vlen,
"-%s%s",
w, w64);
4223 const char * testname =
skipdev(name);
4224 if (!strncmp(testname,
"csmi", 4))
4226 if (!strncmp(testname,
"tw_cli", 6))
4248 int disknum = -1, n1 = -1, n2 = -1;
4252 if (sscanf(type,
"areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) {
4253 if (!(1 <= disknum && disknum <= 128)) {
4254 set_err(EINVAL,
"Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum);
4257 if (!(1 <= encnum && encnum <= 8)) {
4258 set_err(EINVAL,
"Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum);
4263#define ARECA_MAX_CTLR_NUM 16
4266 if (sscanf(name,
"arcmsr%d%n", &ctlrindex, &n1) >= 1 && n1 == (
int)strlen(name)) {
4272 memset(devpath, 0,
sizeof(devpath));
4273 snprintf(devpath,
sizeof(devpath),
"\\\\.\\scsi%d:", idx);
4276 if(ctlrindex-- == 0) {
4282 set_err(ENOENT,
"No Areca controller found");
4285 set_err(EINVAL,
"Option -d areca,N/E requires device name /dev/arcmsrX");
4290 unsigned ctrnum,
lun, target;
4293 if ( sscanf(type,
"aacraid,%u,%u,%u%n,force%n", &ctrnum, &
lun, &target, &n1, &n2) >= 3
4294 && (n1 == (
int)strlen(type) || n2 == (
int)strlen(type))) {
4298 "smartmontools AACRAID support is reportedly broken on Windows.\n"
4299 "See https://www.smartmontools.org/ticket/1515 for details.\n"
4300 "Use '-d aacraid,H,L,ID,force' to try anyway at your own risk.\n"
4301 "If you could provide help to fix the problem, please inform\n"
4302 PACKAGE_BUGREPORT
"\n");
4306#define aacraid_MAX_CTLR_NUM 16
4308 set_err(EINVAL,
"aacraid: invalid host number %u", ctrnum);
4316 memset(devpath, 0,
sizeof(devpath));
4317 unsigned ctlrindex = 0;
4320 snprintf(subKey,
sizeof(subKey),
"HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port %d", portNum);
4322 long regStatus = RegOpenKeyExA(HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, &hScsiKey);
4323 if (regStatus == ERROR_SUCCESS){
4324 char driverName[20];
4325 DWORD driverNameSize =
sizeof(driverName);
4327 regStatus = RegQueryValueExA(hScsiKey,
"Driver", NULL, ®Type, (LPBYTE) driverName, &driverNameSize);
4328 if (regStatus == ERROR_SUCCESS){
4329 if (regType == REG_SZ){
4330 if (stricmp(driverName,
"arcsas") == 0){
4331 if(ctrnum == ctlrindex){
4332 snprintf(devpath,
sizeof(devpath),
"\\\\.\\Scsi%d:", portNum);
4340 RegCloseKey(hScsiKey);
4344 set_err(EINVAL,
"aacraid: host %u not found", ctrnum);
4353 return "aacraid,H,L,ID, areca,N[/E]";
4363 if (!
data->desc.VendorIdOffset)
4365 if (strcmp(
data->raw +
data->desc.VendorIdOffset,
"ATA "))
4373 if (!(
data->desc.VendorIdOffset &&
data->desc.ProductIdOffset))
4375 const char * vendor =
data->raw +
data->desc.VendorIdOffset;
4376 if (!(!strnicmp(vendor,
"Intel", 5) && strspn(vendor+5,
" ") == strlen(vendor+5)))
4378 if (strnicmp(
data->raw +
data->desc.ProductIdOffset,
"Raid ", 5))
4392 switch ((
int)
data.desc.BusType) {
4401 memset(ata_version_ex, 0,
sizeof(*ata_version_ex));
4444 HANDLE h = CreateFileA(path, GENERIC_READ|GENERIC_WRITE,
4445 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
4446 if (h == INVALID_HANDLE_VALUE) {
4448 h = CreateFileA(path, 0,
4449 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
4450 if (h == INVALID_HANDLE_VALUE)
4454 pout(
" %s: successfully opened%s\n", path, (!admin ?
" (without admin rights)" :
""));
4464 snprintf(path,
sizeof(path)-1,
"\\\\.\\PhysicalDrive%d", drive);
4477 snprintf(path,
sizeof(path)-1,
"\\\\.\\%c:",
'A'+drive);
4483 phydrive = logdrive = -1;
4486 if (!strncmp(name,
"st", 2))
4488 if (!strncmp(name,
"nst", 3))
4490 if (!strncmp(name,
"tape", 4))
4494 if (logdrive >= 0) {
4499 char drive[2+1] =
"";
4500 if (sscanf(name,
"sd%2[a-z]", drive) == 1) {
4505 if (sscanf(name,
"pd%d", &phydrive) == 1 && phydrive >= 0)
4513 int phydrive,
int logdrive )
4516 unsigned short vendor_id = 0, product_id = 0;
4517 if (!
get_usb_id(phydrive, logdrive, vendor_id, product_id)) {
4518 set_err(EINVAL,
"Unable to read USB device ID");
4533 const char * testname =
skipdev(name);
4546 int phydrive = -1, logdrive = -1;
4570 const char * type,
const char * pattern )
4573 set_err(EINVAL,
"DEVICESCAN with pattern not implemented yet");
4579 char type2[16+1] =
"";
4582 if (!strcmp(type,
"pd")) {
4586 else if (sscanf(type,
"%16[^,],pd%n", type2, &nc) == 1 &&
4587 nc == (
int)strlen(type)) {
4594 bool ata, scsi,
sat, usb, csmi, nvme;
4596 ata = scsi = usb =
sat = csmi =
true;
4597#ifdef WITH_NVME_DEVICESCAN
4604 ata = scsi = usb =
sat = csmi = nvme =
false;
4605 if (!strcmp(type,
"ata"))
4607 else if (!strcmp(type,
"scsi"))
4609 else if (!strcmp(type,
"sat"))
4611 else if (!strcmp(type,
"usb"))
4613 else if (!strcmp(type,
"csmi"))
4615 else if (!strcmp(type,
"nvme"))
4619 "Invalid type '%s', valid arguments are: ata[,pd], scsi[,pd], "
4620 "sat[,pd], usb[,pd], csmi, nvme, pd", type);
4627 if (ata || scsi ||
sat || usb || nvme) {
4629 const int max_raid = 2;
4630 bool raid_seen[max_raid] = {
false,
false};
4632 for (
int i = 0; i < 128; i++) {
4634 snprintf(name,
sizeof(name),
"/dev/pd%d", i);
4635 else if (i +
'a' <=
'z')
4636 snprintf(name,
sizeof(name),
"/dev/sd%c", i +
'a');
4638 snprintf(name,
sizeof(name),
"/dev/sd%c%c",
4639 i / (
'z'-
'a'+1) - 1 +
'a',
4640 i % (
'z'-
'a'+1) +
'a');
4658 int len = strlen(name);
4659 for (
unsigned int pi = 0; pi < 32; pi++) {
4661 snprintf(name+len,
sizeof(name)-1-len,
",%u", pi);
4713 for (
int i = 0; i <= 9; i++) {
4714 snprintf(name,
sizeof(name)-1,
"/dev/csmi%d,0", i);
4723 for (
int pi = 0; pi < 32; pi++) {
4724 if (!(ports_used & (1U << pi)))
4726 snprintf(name,
sizeof(name)-1,
"/dev/csmi%d,%d", i, pi);
4735 for (
int i = 0; i < 32; i++) {
4736 snprintf(name,
sizeof(name)-1,
"/dev/nvme%d", i);
4744 if (!test_dev.
probe())
4746 if (++nvme_cnt >= 10)
4750 for (
int i = 0; i < nvme_cnt; i++) {
4751 snprintf(name,
sizeof(name)-1,
"/dev/nvme%d", i);
4762 if (strcmp(appname,
"smartctl"))
4764 return "=================================================== SMARTCTL EXAMPLES =====\n\n"
4765 " smartctl -a /dev/sda (Prints all SMART information)\n\n"
4766 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/sda\n"
4767 " (Enables SMART on first disk)\n\n"
4768 " smartctl -t long /dev/sda (Executes extended disk self-test)\n\n"
4769 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/sda\n"
4770 " (Prints Self-Test & Attribute errors)\n"
4771 " smartctl -a /dev/sda\n"
4772 " (Prints all information for disk on PhysicalDrive 0)\n"
4773 " smartctl -a /dev/pd3\n"
4774 " (Prints all information for disk on PhysicalDrive 3)\n"
4775 " smartctl -a /dev/tape1\n"
4776 " (Prints all information for SCSI tape on Tape 1)\n"
4777 " smartctl -A /dev/hdb,3\n"
4778 " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n"
4779 " smartctl -A /dev/tw_cli/c0/p1\n"
4780 " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n"
4781 " smartctl --all --device=areca,3/1 /dev/arcmsr0\n"
4782 " (Prints all SMART info for 3rd ATA disk of the 1st enclosure\n"
4783 " on 1st Areca RAID controller)\n"
4785 " ATA SMART access methods and ordering may be specified by modifiers\n"
4786 " following the device name: /dev/hdX:[saicm], where\n"
4787 " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n"
4788 " 'i': IOCTL_IDE_PASS_THROUGH, 'f': IOCTL_STORAGE_*,\n"
4789 " 'm': IOCTL_SCSI_MINIPORT_*.\n"
4799 SYSTEM_POWER_STATUS ps;
4800 if (!GetSystemPowerStatus(&ps))
4801 return set_err(ENOSYS,
"Unknown power status");
4802 if (ps.ACLineStatus != 1) {
4803 SetThreadExecutionState(ES_CONTINUOUS);
4804 if (ps.ACLineStatus == 0)
4807 set_err(EIO,
"Unknown AC line status");
4812 if (!SetThreadExecutionState(ES_CONTINUOUS | (disable ? ES_SYSTEM_REQUIRED : 0)))
4828 BOOL (WINAPI * SetDllDirectoryA_p)(LPCSTR) =
4829 (BOOL (WINAPI *)(LPCSTR))(
void *)
4830 GetProcAddress(GetModuleHandleA(
"kernel32.dll"),
"SetDllDirectoryA");
4831 if (SetDllDirectoryA_p)
4832 SetDllDirectoryA_p(
"");
4846 char path[MAX_PATH];
4848 if (!GetModuleFileNameA(GetModuleHandleA(0), path,
sizeof(path)))
4849 throw std::runtime_error(
"GetModuleFileName() failed");
4852 for (
int i = 0; path[i]; i++)
4853 if (path[i] ==
'\\') {
4854 path[i] =
'/'; sl = i;
#define SRB_FUNCTION_EXECUTE_SCSI
unsigned char ata_debugmode
#define ATA_SMART_AUTO_OFFLINE
#define ATA_IDENTIFY_DEVICE
#define ATA_SMART_WRITE_LOG_SECTOR
#define ATA_IDENTIFY_PACKET_DEVICE
#define ATA_SMART_READ_VALUES
#define ATA_SMART_READ_THRESHOLDS
#define ATA_SMART_READ_LOG_SECTOR
#define ATA_SMART_IMMEDIATE_OFFLINE
#define ATA_SMART_AUTOSAVE
#define ATA_SMART_DISABLE
#define ATA_CHECK_POWER_MODE
Smart pointer class for device pointers.
device_type * release()
Return the pointer and release ownership.
Adapter class to implement new ATA pass through old interface.
bool ata_cmd_is_supported(const ata_cmd_in &in, unsigned flags, const char *type=0)
Check command input parameters.
virtual int arcmsr_get_dev_type()
void set_disknum(int disknum)
void set_encnum(int encnum)
virtual bool arcmsr_probe()
unsigned get_nsid() const
Get namespace id.
bool set_nvme_err(nvme_cmd_out &out, unsigned status, const char *msg=0)
Set last error number and message if pass-through returns NVMe error status.
void set_nsid(unsigned nsid)
Set namespace id.
virtual bool ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out) override
ATA pass through.
unsigned get_ports_used()
Get bitmask of used ports.
bool select_port(int port)
Select physical drive.
CSMI_SAS_PHY_ENTITY m_phy_ent
CSMI info for this phy.
signed char port_2_index_map[max_number_of_ports]
static bool guess_amd_drives(CSMI_SAS_PHY_INFO &phy_info, unsigned max_phy_drives)
virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER *csmi_buffer, unsigned csmi_bufsiz)=0
Call platform-specific CSMI ioctl.
const CSMI_SAS_PHY_ENTITY & get_phy_ent() const
Get info for selected physical drive.
int get_phy_info(CSMI_SAS_PHY_INFO &phy_info, port_2_index_map &p2i)
Get phy info and port mapping, return #ports or -1 on error.
win10_nvme_device(smart_interface *intf, const char *dev_name, const char *req_type, unsigned nsid)
virtual bool open() override
Open device, return false on error.
bool nvme_storage_protocol_command(const nvme_cmd_in &in, nvme_cmd_out &out)
virtual bool nvme_pass_through(const nvme_cmd_in &in, nvme_cmd_out &out) override
NVMe pass through.
bool nvme_storage_query_property(const nvme_cmd_in &in, nvme_cmd_out &out)
virtual bool open() override
Open device, return false on error.
virtual bool scsi_pass_through(struct scsi_cmnd_io *iop) override
SCSI pass through.
win_aacraid_device(smart_interface *intf, const char *dev_name, unsigned int ctrnum, unsigned int target, unsigned int lun)
virtual ~win_aacraid_device()
virtual bool arcmsr_unlock() override
virtual bool open() override
Open device, return false on error.
virtual smart_device * autodetect_open() override
Open device with autodetection support.
win_areca_ata_device(smart_interface *intf, const char *dev_name, int disknum, int encnum=1)
virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io *iop) override
virtual bool arcmsr_lock() override
virtual smart_device * autodetect_open() override
Open device with autodetection support.
virtual bool open() override
Open device, return false on error.
virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io *iop) override
virtual bool arcmsr_lock() override
virtual bool arcmsr_unlock() override
win_areca_scsi_device(smart_interface *intf, const char *dev_name, int disknum, int encnum=1)
virtual ~win_ata_device()
virtual bool is_powered_down() override
Early test if device is powered up or down.
win_ata_device(smart_interface *intf, const char *dev_name, const char *req_type)
virtual bool ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out) override
ATA pass through.
virtual bool ata_identify_is_cached() const override
Return true if OS caches ATA identify sector.
virtual bool open() override
Open device, return false on error.
virtual bool open() override
Open device, return false on error.
win_csmi_device(smart_interface *intf, const char *dev_name, const char *req_type)
virtual bool is_open() const override
Return true if device is open.
virtual bool close() override
Close device, return false on error.
HANDLE m_fh
Controller device handle.
virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER *csmi_buffer, unsigned csmi_bufsiz) override
Call platform-specific CSMI ioctl.
virtual ~win_csmi_device()
win_nvme_device(smart_interface *intf, const char *dev_name, const char *req_type, unsigned nsid)
virtual bool open() override
Open device, return false on error.
virtual bool nvme_pass_through(const nvme_cmd_in &in, nvme_cmd_out &out) override
NVMe pass through.
win_scsi_device(smart_interface *intf, const char *dev_name, const char *req_type)
virtual bool scsi_pass_through(scsi_cmnd_io *iop) override
SCSI pass through.
virtual bool open() override
Open device, return false on error.
virtual ~win_smart_device()
HANDLE get_fh() const
Return handle for derived classes.
virtual bool close()
Close device, return false on error.
void set_fh(HANDLE fh)
Set handle for open() in derived classes.
virtual bool is_open() const
Return true if device is open.
virtual std::string get_os_version_str() override
Return info string about build host and/or OS version.
virtual nvme_device * get_nvme_device(const char *name, const char *type, unsigned nsid) override
Return standard NVMe device.
virtual scsi_device * get_scsi_device(const char *name, const char *type) override
Return standard SCSI device.
virtual bool disable_system_auto_standby(bool disable) override
Disable/Enable system auto standby/sleep mode.
virtual bool scan_smart_devices(smart_device_list &devlist, const char *type, const char *pattern=0) override
Fill 'devlist' with devices of some 'type' with device names specified by some optional 'pattern'.
virtual ata_device * get_ata_device(const char *name, const char *type) override
Return standard ATA device.
virtual std::string get_valid_custom_dev_types_str() override
Return valid 'type' args accepted by above.
virtual smart_device * get_custom_smart_device(const char *name, const char *type) override
Return device for platform specific 'type'.
virtual std::string get_app_examples(const char *appname) override
Return example string for program 'appname'.
virtual smart_device * autodetect_smart_device(const char *name) override
Autodetect device if no device type specified.
smart_device * get_usb_device(const char *name, int phydrive, int logdrive=-1)
virtual bool close() override
Close device, return false on error.
virtual bool open() override
Open device, return false on error.
virtual bool is_open() const override
Return true if device is open.
ata_identify_device m_ident_buf
win_tw_cli_device(smart_interface *intf, const char *dev_name, const char *req_type)
virtual int ata_command_interface(smart_command_set command, int select, char *data)
Old ATA interface called by ata_pass_through()
ata_smart_values m_smart_buf
Wrapper class for POSIX regex(3) or std::regex Supports copy & assignment and is compatible with STL ...
bool execute(const char *str, unsigned nmatch, match_range *pmatch) const
Return true if substring matches pattern, fill match_range array.
List of devices for DEVICESCAN.
void push_back(smart_device *dev)
Base class for all devices.
int get_errno() const
Get last error number.
smart_interface * smi()
Get interface which produced this object.
const char * get_errmsg() const
Get last error message.
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
bool is_ata() const
Return true if ATA device.
device_info & set_info()
R/W access to device info struct.
const char * get_dev_name() const
Get device (path)name.
void clear_err()
Clear last error info.
The platform interface abstraction.
static void set(smart_interface *intf)
Set interface to use, must be called from init().
virtual const char * get_usb_dev_type_by_id(int vendor_id, int product_id, int version=-1)
Get type name for USB device with known VENDOR:PRODUCT ID.
virtual ata_device * get_sat_device(const char *type, scsi_device *scsidev)
Return ATA->SCSI filter for a SAT or USB 'type'.
static void init()
Initialize platform interface and register with smi().
virtual smart_device * get_scsi_passthrough_device(const char *type, scsi_device *scsidev)
Return ATA->SCSI of NVMe->SCSI filter for a SAT, SNT or USB 'type'.
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
#define CSMI_SAS_LINK_RATE_NEGOTIATED
#define CSMI_SAS_END_DEVICE
#define CSMI_RAID_SIGNATURE
#define CSMI_SAS_STP_READ
#define CSMI_SAS_NO_DEVICE_ATTACHED
#define CSMI_SAS_STP_WRITE
#define CSMI_SAS_STP_UNSPECIFIED
#define CSMI_SAS_PROTOCOL_STP
#define CSMI_SAS_PROTOCOL_SATA
#define CSMI_SAS_SIGNATURE
#define CSMI_ALL_SIGNATURE
static bool match(const char *pattern, const char *str)
static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX *ata_version_ex)
static long scsi_pass_through_direct(HANDLE fd, UCHAR targetid, struct scsi_cmnd_io *iop)
Areca RAID support.
static void print_ide_regs_io(const IDEREGS *ri, const IDEREGS *ro)
static int get_clipboard(char *data, int datasize)
static int update_3ware_devicemap_ioctl(HANDLE hdevice)
static win_dev_type get_log_drive_type(int drive)
static bool get_serial_from_wmi(int drive, ata_identify_device *id)
static bool is_intel_raid_volume(const STORAGE_DEVICE_DESCRIPTOR_DATA *data)
static int get_identify_from_device_property(HANDLE hdevice, ata_identify_device *id)
static int get_device_power_state(HANDLE hdevice)
static win_dev_type get_controller_type(HANDLE hdevice, bool admin, GETVERSIONINPARAMS_EX *ata_version_ex)
static win_dev_type get_dev_type(const char *name, int &phydrive, int &logdrive)
static bool get_usb_id(int phydrive, int logdrive, unsigned short &vendor_id, unsigned short &product_id)
static void print_ide_regs(const IDEREGS *r, int out)
static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS *regs, IDEREGS *prev_regs, char *data, int datasize)
static int smart_get_version(HANDLE hdevice, GETVERSIONINPARAMS_EX *ata_version_ex=0)
static int storage_predict_failure_ioctl(HANDLE hdevice, char *data=0)
static int is_permissive()
static int drive_letter(const char *s)
static int smart_ioctl(HANDLE hdevice, IDEREGS *regs, char *data, unsigned datasize, int port)
static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS *regs, char *data, int datasize)
static long scsi_pass_through_indirect(HANDLE h, SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER *sbd)
static bool is_sat(const STORAGE_DEVICE_DESCRIPTOR_DATA *data)
static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS *regs, char *data, unsigned datasize)
static int sdxy_to_phydrive(const char(&xy)[2+1])
static const char * skipdev(const char *s)
static const char * ata_get_def_options()
static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS *regs, char *data, int datasize, int port)
static int storage_query_property_ioctl(HANDLE hdevice, STORAGE_DEVICE_DESCRIPTOR_DATA *data)
static void copy_swapped(unsigned char *dest, const char *src, int destsize)
static const char * findstr(const char *str, const char *sub)
struct win10::_STORAGE_PROTOCOL_SPECIFIC_DATA STORAGE_PROTOCOL_SPECIFIC_DATA
enum win10::_STORAGE_PROTOCOL_TYPE STORAGE_PROTOCOL_TYPE
enum win10::_STORAGE_PROTOCOL_NVME_DATA_TYPE STORAGE_PROTOCOL_NVME_DATA_TYPE
const STORAGE_PROPERTY_ID StorageDeviceProtocolSpecificProperty
const STORAGE_PROPERTY_ID StorageAdapterProtocolSpecificProperty
_STORAGE_PROTOCOL_NVME_DATA_TYPE
unsigned char nvme_debugmode
unsigned char failuretest_permissive
struct _NVME_PASS_THROUGH_IOCTL NVME_PASS_THROUGH_IOCTL
unsigned char failuretest_permissive
#define STORAGE_PROTOCOL_COMMAND_LENGTH_NVME
const char * os_win32_cpp_cvsid
#define STORAGE_PROTOCOL_STRUCTURE_VERSION
#define ARECA_MAX_CTLR_NUM
#define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
#define IOCTL_SCSI_MINIPORT_DISABLE_SMART
std::string get_exe_dir()
#define STORAGE_PROTOCOL_SPECIFIC_NVME_ADMIN_COMMAND
struct _SENDCMDINPARAMS_EX SENDCMDINPARAMS_EX
#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
#define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG
#define IOCTL_STORAGE_PROTOCOL_COMMAND
#define SELECT_WIN_32_64(x32, x64)
#define IOCTL_SCSI_MINIPORT_IDENTIFY
#define aacraid_MAX_CTLR_NUM
#define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
#define SMART_VENDOR_3WARE
#define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
#define IOCTL_SCSI_MINIPORT_ENABLE_SMART
#define NVME_PASS_THROUGH_SRB_IO_CODE
#define IOCTL_SCSI_MINIPORT_READ_SMART_LOG
#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE
#define IOCTL_IDE_PASS_THROUGH
#define IOCTL_SCSI_MINIPORT_RETURN_STATUS
struct _GETVERSIONINPARAMS_EX GETVERSIONINPARAMS_EX
#define IOCTL_SCSI_MINIPORT_SMART_VERSION
struct _STORAGE_PROTOCOL_COMMAND STORAGE_PROTOCOL_COMMAND
#define STORAGE_PROTOCOL_COMMAND_FLAG_ADAPTER_REQUEST
void dStrHex(const uint8_t *up, int len, int no_ascii)
unsigned char scsi_debugmode
const char * scsi_get_opcode_name(const uint8_t *cdbp)
#define DXFER_FROM_DEVICE
#define SCSI_STATUS_CHECK_CONDITION
void pout(const char *fmt,...)
struct NVME_COMMAND::@114::@115 GENERAL
union NVME_COMMAND::@114 u
CSMI_SAS_DRIVER_INFO Information
CSMI_SAS_IDENTIFY Identify
CSMI_SAS_IDENTIFY Attached
CSMI_SAS_PHY_INFO Information
CSMI_SAS_PHY_ENTITY Phy[32]
CSMI_SAS_RAID_INFO Information
CSMI_SAS_STP_PASSTHRU Parameters
CSMI_SAS_STP_PASSTHRU_STATUS Status
win10::STORAGE_PROTOCOL_TYPE ProtocolType
DWORD DataToDeviceBufferOffset
DWORD DataFromDeviceBufferOffset
DWORD DataFromDeviceTransferLength
DWORD FixedProtocolReturnData
DWORD DataToDeviceTransferLength
ATA pass through input parameters.
enum ata_cmd_in::@29 direction
I/O direction.
void * buffer
Pointer to data buffer.
ata_in_regs_48bit in_regs
Input registers.
unsigned size
Size of buffer.
ATA pass through output parameters.
ata_out_regs_48bit out_regs
Output registers.
bool is_48bit_cmd() const
Return true if 48-bit command.
ata_in_regs prev
"previous content"
ATA Input registers (for 28-bit commands)
ata_register sector_count
ata_out_regs prev
read with HOB=1
ATA Output registers (for 28-bit commands)
ata_register sector_count
NVMe pass through input parameters.
unsigned char direction() const
Get I/O direction from opcode.
unsigned char opcode
Opcode (CDW0 07:00)
unsigned size
Size of buffer.
unsigned cdw15
Cmd specific.
unsigned nsid
Namespace ID.
void set_data_in(unsigned char op, void *buf, unsigned sz)
void * buffer
Pointer to data buffer.
NVMe pass through output parameters.
unsigned result
Command specific result (DW0)
SCSI_PASS_THROUGH_DIRECT spt
STORAGE_QUERY_TYPE QueryType
struct os_win32::STORAGE_PROTOCOL_SPECIFIC_QUERY_WITH_BUFFER::@117 PropertyQuery
STORAGE_PROPERTY_ID PropertyId
win10::STORAGE_PROTOCOL_SPECIFIC_DATA ProtocolSpecific
std::string info_name
Informal name.
std::string dev_type
Actual device type.
ULONG FixedProtocolReturnData
ULONG ProtocolDataRequestValue
STORAGE_PROTOCOL_TYPE ProtocolType
ULONG ProtocolDataRequestSubValue
STORAGE_DEVICE_DESCRIPTOR desc
std::string strprintf(const char *fmt,...)
bool nonempty(const void *data, int size)
bool str_starts_with(const char *str, const char *prefix)