Ticket #645: 20211021-1604.patch

File 20211021-1604.patch, 32.2 KB (added by kenjiuno, 3 years ago)

win32 HighPoint RocketRAID support

  • trunk/smartmontools/Makefile.am

    diff --git a/trunk/smartmontools/Makefile.am b/trunk/smartmontools/Makefile.am
    a b  
    200200smartd_SOURCES += \
    201201        os_win32/daemon_win32.cpp \
    202202        os_win32/daemon_win32.h \
     203        os_win32/hpt.h \
    203204        os_win32/popen_win32.cpp \
    204205        os_win32/popen.h \
    205206        os_win32/syslog_win32.cpp \
  • trunk/smartmontools/os_win32.cpp

    diff --git a/trunk/smartmontools/os_win32.cpp b/trunk/smartmontools/os_win32.cpp
    a b  
    5959// aacraid support
    6060#include "aacraid.h"
    6161
     62// HPT experimental support
     63#include "os_win32/hpt.h"
     64
    6265#ifndef _WIN64
    6366#define SELECT_WIN_32_64(x32, x64) (x32)
    6467#else
     
    38953898}
    38963899
    38973900
     3901
     3902//////////////////////////////////////////////////////////////////////
     3903// win32_highpoint_common
     3904
     3905class win32_highpoint_common
     3906: virtual public /*extends*/ win_smart_device
     3907{
     3908public:
     3909  win32_highpoint_common()
     3910    : win_smart_device(never_called)
     3911    { }
     3912
     3913  bool hpt_ioctl(unsigned code, IOCTL_HEADER * ioctl_buffer,
     3914    unsigned ioctl_bufsiz);
     3915
     3916  bool get_version(int & version);
     3917
     3918  bool open_scsi(int n);
     3919
     3920  /**
     3921   * return number of ids written. -1 if error.
     3922   */
     3923  bool get_phys_devices(int ids_count, int device_ids[], int & ids_written);
     3924
     3925  /**
     3926   * return number of ids written. -1 if error.
     3927   */
     3928  bool get_logical_devices(int ids_count, int device_ids[], int & ids_written);
     3929
     3930  /**
     3931   * 0 if success.
     3932   */
     3933  bool get_device_info(int device_id, hpt::LOGICAL_DEVICE_INFO * pInfo);
     3934
     3935  /**
     3936   * 0 if success.
     3937   */
     3938  bool get_controller_info_v2(int controller_id, hpt::CONTROLLER_INFO_V2 * out_buf);
     3939
     3940  /**
     3941   * 0 if success.
     3942   */
     3943  bool get_channel_info(int controller_id, int bus_num, hpt::CHANNEL_INFO * out_buf);
     3944
     3945protected:
     3946
     3947};
     3948
     3949bool win32_highpoint_common::open_scsi(int n)
     3950{
     3951  // TODO: Use common open function for all devices using "\\.\ScsiN:"
     3952  char devpath[32];
     3953  snprintf(devpath, sizeof(devpath)-1, "\\\\.\\Scsi%d:", n);
     3954
     3955  HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
     3956    FILE_SHARE_READ|FILE_SHARE_WRITE,
     3957    (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, 0);
     3958
     3959  if (h == INVALID_HANDLE_VALUE) {
     3960    long err = GetLastError();
     3961    if (scsi_debugmode > 1)
     3962      pout("  %s: Open failed, Error=%ld\n", devpath, err);
     3963    if (err == ERROR_FILE_NOT_FOUND)
     3964      set_err(ENOENT, "%s: not found", devpath);
     3965    else if (err == ERROR_ACCESS_DENIED)
     3966      set_err(EACCES, "%s: access denied", devpath);
     3967    else
     3968      set_err(EIO, "%s: Error=%ld", devpath, err);
     3969    return false;
     3970  }
     3971
     3972  if (scsi_debugmode > 1)
     3973    pout("  %s: successfully opened\n", devpath);
     3974
     3975  set_fh(h);
     3976  return true; 
     3977}
     3978
     3979bool win32_highpoint_common::hpt_ioctl(unsigned code, IOCTL_HEADER * ioctl_buffer,
     3980  unsigned ioctl_bufsiz)
     3981{
     3982  // Set header
     3983  ioctl_buffer->HeaderLength = sizeof(IOCTL_HEADER);
     3984  memcpy((char *)ioctl_buffer->Signature, "HPT-CTRL\0", sizeof(ioctl_buffer->Signature));
     3985  ioctl_buffer->Timeout = CSMI_SAS_TIMEOUT;
     3986  ioctl_buffer->ControlCode = HPT_CTL_CODE(code);
     3987  ioctl_buffer->ReturnCode = 0;
     3988  ioctl_buffer->Length = ioctl_bufsiz - sizeof(IOCTL_HEADER);
     3989
     3990  // Call function
     3991  DWORD num_out = 0;
     3992  if (!DeviceIoControl(get_fh(), IOCTL_SCSI_MINIPORT,
     3993    ioctl_buffer, ioctl_bufsiz, ioctl_buffer, ioctl_bufsiz, &num_out, (OVERLAPPED*)0)) {
     3994    long err = GetLastError();
     3995    if (scsi_debugmode)
     3996      pout("  IOCTL_SCSI_MINIPORT(HPT_CTL_CODE_%u) failed, Error=%ld\n", code, err);
     3997    if (   err == ERROR_INVALID_FUNCTION
     3998        || err == ERROR_NOT_SUPPORTED
     3999        || err == ERROR_DEV_NOT_EXIST)
     4000      return set_err(ENOSYS, "HPT command is not supported (Error=%ld)", err);
     4001    else
     4002      return set_err(EIO, "HPT command(%u) failed with Error=%ld", code, err);
     4003  }
     4004
     4005  // Check result
     4006  if (ioctl_buffer->ReturnCode) {
     4007    if (scsi_debugmode) {
     4008      pout("  IOCTL_SCSI_MINIPORT(HPT_CTL_CODE_%u) failed, ReturnCode=%u\n",
     4009        code, (unsigned)ioctl_buffer->ReturnCode);
     4010    }
     4011    return set_err(EIO, "HPT command(%u) failed with ReturnCode=%u", code, (unsigned)ioctl_buffer->ReturnCode);
     4012  }
     4013
     4014  if (scsi_debugmode > 1)
     4015    pout("  IOCTL_SCSI_MINIPORT(HPT_CTL_CODE_%u) succeeded, bytes returned: %u\n", code, (unsigned)num_out);
     4016
     4017  return true;
     4018}
     4019
     4020bool win32_highpoint_common::get_version(int & version)
     4021{
     4022  hpt::GET_VERSION_BUFFER buf;
     4023  memset(&buf, 0, sizeof(buf));
     4024  buf.io_len.out_len = 4;
     4025
     4026  if (!hpt_ioctl(HPT_IOCTL_CODE_GET_VERSION, &buf.ioctl_header, sizeof(buf))) {
     4027    return false;
     4028  }
     4029
     4030  version = buf.version;
     4031  return true;
     4032}
     4033
     4034
     4035bool win32_highpoint_common::get_phys_devices(
     4036  int ids_count, int device_ids[], int & ids_written
     4037)
     4038{
     4039  hpt::GET_PHYSICAL_DEVICES_BUFFER buf;
     4040  memset(&buf, 0, sizeof(buf));
     4041  buf.io_len.in_len = 4;
     4042  buf.io_len.out_len = 4 + 4 * 256;
     4043  buf.numIdsToWrite = 256;
     4044
     4045  if (!hpt_ioctl(HPT_IOCTL_CODE_GET_PHYSICAL_DEVICES, &buf.ioctl_header, sizeof(buf))) {
     4046    return false;
     4047  }
     4048
     4049  memcpy(device_ids, buf.deviceIds, 4 * std::min(256U, (uint32_t)ids_count));
     4050  ids_written = buf.numIdsWritten;
     4051  return true;
     4052}
     4053
     4054bool win32_highpoint_common::get_logical_devices(
     4055  int ids_count, int device_ids[], int & ids_written
     4056)
     4057{
     4058  hpt::GET_LOGICAL_DEVICES_BUFFER buf;
     4059  memset(&buf, 0, sizeof(buf));
     4060  buf.io_len.in_len = 4;
     4061  buf.io_len.out_len = 4 + 4 * 256;
     4062  buf.numIdsToWrite = 256;
     4063
     4064  if (!hpt_ioctl(HPT_IOCTL_CODE_GET_LOGICAL_DEVICES, &buf.ioctl_header, sizeof(buf))) {
     4065    return false;
     4066  }
     4067
     4068  memcpy(device_ids, buf.deviceIds, 4 * std::min(256U, (uint32_t)ids_count));
     4069  ids_written = buf.numIdsWritten;
     4070  return true;
     4071}
     4072
     4073bool win32_highpoint_common::get_device_info(int device_id, hpt::LOGICAL_DEVICE_INFO * out_buf)
     4074{
     4075  hpt::GET_LOGICAL_DEVICE_INFO buf;
     4076  memset(&buf, 0, sizeof(buf));
     4077  buf.io_len.in_len = 4;
     4078  buf.io_len.out_len = sizeof(hpt::LOGICAL_DEVICE_INFO);
     4079  buf.device_id = device_id;
     4080
     4081  if (!hpt_ioctl(HPT_IOCTL_CODE_GET_DEVICE_INFO, &buf.ioctl_header, sizeof(buf))) {
     4082    return false;
     4083  }
     4084
     4085  memcpy(out_buf, &buf.out_buf, sizeof(hpt::LOGICAL_DEVICE_INFO));
     4086  return true;
     4087}
     4088
     4089bool win32_highpoint_common::get_controller_info_v2(int controller_id, hpt::CONTROLLER_INFO_V2 * out_buf)
     4090{
     4091  hpt::GET_CONTROLLER_INFO_V2 buf;
     4092  memset(&buf, 0, sizeof(buf));
     4093  buf.io_len.in_len = 4;
     4094  buf.io_len.out_len = sizeof(hpt::CONTROLLER_INFO_V2);
     4095  buf.controller_id = controller_id - 1;
     4096
     4097  if (!hpt_ioctl(HPT_IOCTL_CODE_GET_CONTROLLER_INFO_V2, &buf.ioctl_header, sizeof(buf))) {
     4098    return false;
     4099  }
     4100
     4101  memcpy(out_buf, &buf.out_buf, sizeof(hpt::CONTROLLER_INFO_V2));
     4102  return true;
     4103}
     4104
     4105bool win32_highpoint_common::get_channel_info(int controller_id, int bus_num, hpt::CHANNEL_INFO * out_buf)
     4106{
     4107  hpt::GET_CHANNEL_INFO buf;
     4108  memset(&buf, 0, sizeof(buf));
     4109  buf.io_len.in_len = 8;
     4110  buf.io_len.out_len = sizeof(hpt::CHANNEL_INFO);
     4111  buf.controller_id = controller_id - 1;
     4112  buf.bus_num = bus_num - 1;
     4113
     4114  if (!hpt_ioctl(HPT_IOCTL_CODE_GET_CHANNEL_INFO, &buf.ioctl_header, sizeof(buf))) {
     4115    return false;
     4116  }
     4117
     4118  memcpy(out_buf, &buf.out_buf, sizeof(hpt::CHANNEL_INFO));
     4119  return true;
     4120}
     4121
     4122//////////////////////////////////////////////////////////////////////
     4123// win32_highpoint_ata_device
     4124
     4125class win32_highpoint_ata_device
     4126: public /*implements*/ ata_device,
     4127  public /*extends*/ win32_highpoint_common
     4128{
     4129public:
     4130  win32_highpoint_ata_device(smart_interface * intf,
     4131    const char * dev_name, const char * dev_type, unsigned int scsi_num, unsigned int device_id);
     4132
     4133  virtual bool open() override;
     4134
     4135protected:
     4136  virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
     4137 
     4138private:
     4139  unsigned int m_scsi_num;
     4140  unsigned int m_device_id;
     4141};
     4142
     4143win32_highpoint_ata_device::win32_highpoint_ata_device(smart_interface * intf,
     4144  const char * dev_name, const char * dev_type, unsigned int scsi_num, unsigned int device_id)
     4145: smart_device(intf, dev_name, dev_type, "")
     4146{
     4147  m_scsi_num = scsi_num;
     4148  m_device_id = device_id;
     4149  set_info().info_name = strprintf("%s", dev_name);
     4150}
     4151
     4152bool win32_highpoint_ata_device::open()
     4153{
     4154  if (!open_scsi(m_scsi_num))
     4155    return false;
     4156
     4157  int ver;
     4158  if (!get_version(ver)) {
     4159    close();
     4160    return false;
     4161  }
     4162
     4163  return true;
     4164}
     4165
     4166bool win32_highpoint_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
     4167{
     4168  const bool will_read = in.direction == ata_cmd_in::data_in;
     4169  const bool will_write = in.direction == ata_cmd_in::data_out;
     4170
     4171  const size_t bytes_in_data = will_write ? in.size : 0;
     4172  const size_t bytes_out_data = will_read ? in.size : 0;
     4173
     4174  const size_t blk_size =
     4175    sizeof(IOCTL_HEADER)
     4176    + sizeof(hpt::IO_LEN)
     4177    + sizeof(hpt::IDE_PASS_THROUGH_HEADER)
     4178    + bytes_in_data
     4179    + sizeof(hpt::IDE_PASS_THROUGH_HEADER)
     4180    + bytes_out_data;
     4181
     4182  raw_buffer blk(blk_size);
     4183
     4184  if (!blk.data()) {
     4185    return smart_device::set_err(ENOMEM, "buffer allocation failure");
     4186  }
     4187
     4188  memset(blk.data(), -1, blk_size);
     4189
     4190  uint8_t *blk_iter = blk.data();
     4191 
     4192  IOCTL_HEADER * ioctl_header = reinterpret_cast<IOCTL_HEADER *>(blk_iter);
     4193  blk_iter += sizeof(IOCTL_HEADER);
     4194
     4195  hpt::IO_LEN * io_len = reinterpret_cast<hpt::IO_LEN *>(blk_iter);
     4196  blk_iter += sizeof(hpt::IO_LEN);
     4197
     4198  hpt::IDE_PASS_THROUGH_HEADER * ata_in = reinterpret_cast<hpt::IDE_PASS_THROUGH_HEADER *>(blk_iter);
     4199  blk_iter += sizeof(hpt::IDE_PASS_THROUGH_HEADER);
     4200
     4201  void *data_in = blk_iter;
     4202  blk_iter += bytes_in_data;
     4203
     4204  hpt::IDE_PASS_THROUGH_HEADER * ata_out = reinterpret_cast<hpt::IDE_PASS_THROUGH_HEADER *>(blk_iter);
     4205  blk_iter += sizeof(hpt::IDE_PASS_THROUGH_HEADER);
     4206
     4207  void *data_out = blk_iter;
     4208 
     4209  io_len->in_len = sizeof(hpt::IDE_PASS_THROUGH_HEADER) + bytes_in_data;
     4210  io_len->out_len = sizeof(hpt::IDE_PASS_THROUGH_HEADER) + bytes_out_data;
     4211
     4212  ata_in->id_disk = m_device_id;
     4213  ata_in->features_reg = in.in_regs.features;
     4214  ata_in->sector_count_reg = in.in_regs.sector_count;
     4215  ata_in->lba_low_reg = in.in_regs.lba_low;
     4216  ata_in->lba_mid_reg = in.in_regs.lba_mid;
     4217  ata_in->lba_high_reg = in.in_regs.lba_high;
     4218  ata_in->drive_head_reg = in.in_regs.device;
     4219  ata_in->command_reg = in.in_regs.command;
     4220  ata_in->sectors = in.in_regs.sector_count;
     4221  ata_in->protocol =
     4222    will_read ? IO_COMMAND_READ :
     4223    will_write ? IO_COMMAND_WRITE :
     4224    0;
     4225 
     4226  memcpy(data_in, in.buffer, bytes_in_data);
     4227 
     4228  if (!hpt_ioctl(HPT_IOCTL_CODE_IDE_PASS_THROUGH, ioctl_header, blk_size)) {
     4229    return false;
     4230  }
     4231 
     4232  ata_out_regs_48bit &r = out.out_regs;
     4233  r.error           = ata_out->features_reg;
     4234  r.sector_count_16 = ata_out->sector_count_reg;
     4235  r.lba_low_16      = ata_out->lba_low_reg;
     4236  r.lba_mid_16      = ata_out->lba_mid_reg;
     4237  r.lba_high_16     = ata_out->lba_high_reg;
     4238  r.device          = ata_out->drive_head_reg;
     4239  r.status          = ata_out->command_reg;
     4240
     4241  memcpy(in.buffer, data_out, bytes_out_data);
     4242
     4243  return true;
     4244}
     4245
     4246//////////////////////////////////////////////////////////////////////
     4247// win32_highpoint_sas_device
     4248
     4249class win32_highpoint_sas_device
     4250: public /*implements*/ scsi_device,
     4251  public /*extends*/ win32_highpoint_common
     4252{
     4253public:
     4254  win32_highpoint_sas_device(smart_interface * intf,
     4255    const char * dev_name, const char * dev_type , unsigned int scsi_num, unsigned int device_id);
     4256
     4257  virtual bool open() override;
     4258
     4259protected:
     4260  virtual bool scsi_pass_through(struct scsi_cmnd_io *iop);
     4261
     4262private:
     4263  unsigned int m_scsi_num;
     4264  unsigned int m_device_id;
     4265};
     4266
     4267win32_highpoint_sas_device::win32_highpoint_sas_device(smart_interface * intf,
     4268  const char * dev_name, const char * dev_type, unsigned int scsi_num, unsigned int device_id)
     4269: smart_device(intf, dev_name, dev_type, "")
     4270{
     4271  m_scsi_num = scsi_num;
     4272  m_device_id = device_id;
     4273  set_info().info_name = strprintf("%s", dev_name);
     4274}
     4275
     4276bool win32_highpoint_sas_device::open()
     4277{
     4278  if (!open_scsi(m_scsi_num))
     4279    return false;
     4280
     4281  int ver;
     4282  if (!get_version(ver)) {
     4283    close();
     4284    return false;
     4285  }
     4286
     4287  return true;
     4288}
     4289
     4290bool win32_highpoint_sas_device::scsi_pass_through(struct scsi_cmnd_io *iop)
     4291{
     4292  const bool will_read = iop->dxfer_dir == DXFER_FROM_DEVICE;
     4293  const bool will_write = iop->dxfer_dir == DXFER_TO_DEVICE;
     4294 
     4295  const size_t bytes_in_data = will_write?iop->dxfer_len:0;
     4296  const size_t bytes_out_data = will_read?iop->dxfer_len:0;
     4297 
     4298  const size_t blk_size =
     4299    sizeof(IOCTL_HEADER)
     4300    + sizeof(hpt::IO_LEN)
     4301    + sizeof(hpt::SCSI_PASS_THROUGH_IN)
     4302    + bytes_in_data
     4303    + sizeof(hpt::SCSI_PASS_THROUGH_OUT)
     4304    + bytes_out_data;
     4305
     4306  raw_buffer blk(blk_size);
     4307
     4308  if (!blk.data()) {
     4309    return smart_device::set_err(ENOMEM, "buffer allocation failure");
     4310  }
     4311
     4312  memset(blk.data(), -1, blk_size);
     4313
     4314  uint8_t *blk_iter = blk.data();
     4315 
     4316  IOCTL_HEADER * ioctl_header = reinterpret_cast<IOCTL_HEADER *>(blk_iter);
     4317  blk_iter += sizeof(IOCTL_HEADER);
     4318
     4319  hpt::IO_LEN * io_len = reinterpret_cast<hpt::IO_LEN *>(blk_iter);
     4320  blk_iter += sizeof(hpt::IO_LEN);
     4321
     4322  hpt::SCSI_PASS_THROUGH_IN * scsi_in = reinterpret_cast<hpt::SCSI_PASS_THROUGH_IN *>(blk_iter);
     4323  blk_iter += sizeof(hpt::SCSI_PASS_THROUGH_IN);
     4324
     4325  void *data_in = blk_iter;
     4326  blk_iter += bytes_in_data;
     4327
     4328  hpt::SCSI_PASS_THROUGH_OUT * scsi_out = reinterpret_cast<hpt::SCSI_PASS_THROUGH_OUT *>(blk_iter);
     4329  blk_iter += sizeof(hpt::SCSI_PASS_THROUGH_OUT);
     4330
     4331  void *data_out = blk_iter;
     4332 
     4333  io_len->in_len = sizeof(hpt::SCSI_PASS_THROUGH_IN) + bytes_in_data;
     4334  io_len->out_len = sizeof(hpt::SCSI_PASS_THROUGH_OUT) + bytes_out_data;
     4335
     4336  scsi_in->id_disk = m_device_id;
     4337  scsi_in->protocol =
     4338    will_read ? IO_COMMAND_READ :
     4339    will_write ? IO_COMMAND_WRITE :
     4340    0;
     4341  scsi_in->cdb_length = iop->cmnd_len;
     4342  memcpy(scsi_in->cdb, iop->cmnd, iop->cmnd_len);
     4343  scsi_in->data_length = iop->dxfer_len;
     4344 
     4345  memcpy(data_in, iop->dxferp, bytes_in_data);
     4346
     4347  if (!hpt_ioctl(HPT_IOCTL_CODE_SCSI_PASS_THROUGH, ioctl_header, blk_size)) {
     4348    return false;
     4349  }
     4350
     4351  memcpy(iop->dxferp, data_out, bytes_out_data);
     4352   
     4353  iop->scsi_status = scsi_out->scsi_status;
     4354  iop->resp_sense_len = scsi_out->data_length;
     4355  iop->resid = 0;
     4356 
     4357  return true;
     4358}
     4359
     4360//////////////////////////////////////////////////////////////////////
     4361// hpt::helper
     4362
     4363namespace hpt::helper
     4364{
     4365  typedef enum {
     4366    ata = 0x01,
     4367    sas = 0x02,
     4368    array = 0x04,
     4369
     4370    harddisk = 0x10,
     4371    cdrom = 0x20,
     4372    tape = 0x30,
     4373
     4374    raid0 = 0x0100,
     4375    raid1 = 0x0200,
     4376    raid5 = 0x0300,
     4377    raid6 = 0x0400,
     4378    raid3 = 0x0500,
     4379    raid4 = 0x0600,
     4380    jbod = 0x0700,
     4381    raid1e = 0x0800,
     4382  } device_mask;
     4383
     4384  typedef struct {
     4385    uint32_t cross_hba_controller_id;
     4386
     4387    uint32_t controller_id;
     4388    uint32_t channel;
     4389    uint32_t disknum;
     4390
     4391    uint32_t scsi_num;
     4392    uint32_t device_id;
     4393
     4394    uint32_t dev_mask;
     4395
     4396    char dev_name[16]; // "/dev/scsi0c1"
     4397    char dev_type[16]; // "hpt,L/M/N"
     4398  } found_device;
     4399
     4400  typedef std::vector<found_device> found_device_list;
     4401
     4402  void detect_devices(
     4403    smart_interface * intf,
     4404    found_device_list & out_list
     4405  )
     4406  {
     4407    uint32_t cross_hba_controller_id = 1;
     4408
     4409    for (uint32_t scsi_num = 0; ; scsi_num++) {
     4410      win32_highpoint_ata_device test_dev(intf, "", "", scsi_num, 0);
     4411      if (!test_dev.open()) {
     4412        if (test_dev.get_errno() == ENOENT) {
     4413          break;
     4414        }
     4415        else {
     4416          if (scsi_debugmode > 1) {
     4417            pout("  hpt: scsi_num %u is not a RocketRAID HBA\n", scsi_num);
     4418          }
     4419          continue;
     4420        }
     4421      }
     4422     
     4423      for (uint32_t controller_id = 1; ; controller_id++, cross_hba_controller_id++) {
     4424        CONTROLLER_INFO_V2 ctrl_info;
     4425        if (!test_dev.get_controller_info_v2(controller_id, &ctrl_info)) {
     4426          if (scsi_debugmode > 1) {
     4427            pout("  hpt: scsi_num %u controller_id %u is not available\n", scsi_num, controller_id);
     4428          }
     4429          break;
     4430        }
     4431
     4432        for (uint32_t channel = 1; ; channel++) {
     4433          CHANNEL_INFO chan_info;
     4434          if (!test_dev.get_channel_info(controller_id, channel, &chan_info)) {
     4435            if (scsi_debugmode > 1) {
     4436              pout("  hpt: scsi_num %u controller_id %u channel %u is not available\n"
     4437                , scsi_num, controller_id, channel);
     4438            }
     4439            break;
     4440          }
     4441
     4442          for (uint32_t disknum = 1; disknum <= 2; disknum++) {
     4443            const uint32_t device_id = chan_info.devices[disknum - 1];
     4444            if (device_id == 0) {
     4445              // no device is connected.
     4446              continue;
     4447            }
     4448
     4449            LOGICAL_DEVICE_INFO dev_info;
     4450            if (!test_dev.get_device_info(device_id, &dev_info)) {
     4451              continue;
     4452            }
     4453
     4454            found_device found;
     4455            found.cross_hba_controller_id = cross_hba_controller_id;
     4456
     4457            found.controller_id = controller_id;
     4458            found.channel = channel;
     4459            found.disknum = disknum;
     4460
     4461            found.scsi_num = scsi_num;
     4462            found.device_id = device_id;
     4463
     4464            found.dev_mask = 0;
     4465
     4466            snprintf(found.dev_name, sizeof(found.dev_name)
     4467              , "/dev/scsi%ud%u"
     4468              , scsi_num, device_id);
     4469
     4470            snprintf(found.dev_type, sizeof(found.dev_type)
     4471              , "hpt,%u/%u/%u"
     4472              , cross_hba_controller_id, channel, disknum);
     4473
     4474            switch (dev_info.type) {
     4475              case LDT_DEVICE:
     4476                {
     4477                  // sata device: DEVICE_FLAG_SATA
     4478                  // sas device:  DEVICE_FLAG_SATA|DEVICE_FLAG_SAS
     4479
     4480                  if (dev_info.un.device.flags & DEVICE_FLAG_SAS) {
     4481                    found.dev_mask |= device_mask::sas;
     4482                  }
     4483                  else if (dev_info.un.device.flags & DEVICE_FLAG_SATA) {
     4484                    found.dev_mask |= device_mask::ata;
     4485                  }
     4486
     4487                  found.dev_mask |= (dev_info.un.device.device_type & 0xF) << 4; // PDT_HARDDISK and so on.
     4488                  break;
     4489                }
     4490              case LDT_ARRAY:
     4491                {
     4492                  found.dev_mask |= device_mask::array;
     4493
     4494                  found.dev_mask |= (dev_info.un.array.array_type & 0xFF) << 8; // AT_RAID0 and so on.
     4495                  break;
     4496                }
     4497            }
     4498
     4499            out_list.push_back(found);
     4500
     4501            if (scsi_debugmode > 1) {
     4502              std::string desc = "unknown device";
     4503              {
     4504                if (found.dev_mask & device_mask::sas) {
     4505                  desc = "sas";
     4506                }
     4507                else if (found.dev_mask & device_mask::ata) {
     4508                  desc = "ata";
     4509                }
     4510                else if (found.dev_mask & device_mask::array) {
     4511                  if (found.dev_mask & raid0) desc += "raid0";
     4512                  if (found.dev_mask & raid1) desc += "raid1";
     4513                  if (found.dev_mask & raid5) desc += "raid5";
     4514                  if (found.dev_mask & raid6) desc += "raid6";
     4515                  if (found.dev_mask & raid3) desc += "raid3";
     4516                  if (found.dev_mask & raid4) desc += "raid4";
     4517                  if (found.dev_mask & jbod) desc += "jbod";
     4518                  if (found.dev_mask & raid1e) desc += "raid1e";
     4519                  else desc += "unknown";
     4520
     4521                  desc += " array";
     4522                }
     4523                else {
     4524                  desc = "unknown";
     4525                }
     4526
     4527                if (found.dev_mask & device_mask::harddisk) desc += " harddisk";
     4528                else if (found.dev_mask & device_mask::cdrom) desc += " cdrom";
     4529                else if (found.dev_mask & device_mask::tape) desc += " tape";
     4530                else desc = "unknown";
     4531
     4532                desc += " device";
     4533              }
     4534
     4535              pout("  hpt: %s found hpt,%u/%u/%u (scsi_num %u device_id %u device_mask %08x)\n"
     4536                , desc.c_str()
     4537                , cross_hba_controller_id, channel, disknum
     4538                , scsi_num, device_id, found.dev_mask
     4539              );
     4540            }
     4541
     4542          }
     4543        }
     4544      }
     4545    }
     4546  }
     4547
     4548  smart_device * find_device(
     4549    smart_interface * intf,
     4550    const uint32_t controller,
     4551    const uint32_t channel,
     4552    const uint32_t disknum
     4553  )
     4554  {
     4555    found_device_list list;
     4556    list.reserve(16);
     4557
     4558    detect_devices(intf, list);
     4559
     4560    found_device_list::iterator iter = list.begin();
     4561    for (; iter != list.end(); iter++) {
     4562      if (true
     4563        && iter->cross_hba_controller_id == controller
     4564        && iter->channel == channel
     4565        && iter->disknum == disknum
     4566      )
     4567      {
     4568        if (iter->dev_mask & device_mask::sas) {
     4569          return new win32_highpoint_sas_device(intf,
     4570            iter->dev_name, iter->dev_type, iter->scsi_num, iter->device_id);
     4571        }
     4572        else if (iter->dev_mask & device_mask::ata) {
     4573          return new win32_highpoint_ata_device(intf,
     4574            iter->dev_name, iter->dev_type, iter->scsi_num, iter->device_id);
     4575        }
     4576        return nullptr;
     4577      }
     4578    }
     4579    return nullptr;
     4580  }
     4581}
     4582
    38984583/////////////////////////////////////////////////////////////////////////////
    38994584// win_smart_interface
    39004585// Platform specific interface
     
    41774862    return 0;
    41784863  }
    41794864
     4865  // Highpoint ?
     4866  int controller = -1, channel = -1; disknum = 1;
     4867  n1 = n2 = -1; int n3 = -1;
     4868  if (sscanf(type, "hpt,%n%d/%d%n/%d%n", &n1, &controller, &channel, &n2, &disknum, &n3) >= 2 || n1 == 4) {
     4869    int len = strlen(type);
     4870    if (!(n2 == len || n3 == len)) {
     4871      set_err(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items");
     4872      return 0;
     4873    }
     4874    if (!(1 <= controller && controller <= 8)) {
     4875      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied");
     4876      return 0;
     4877    }
     4878    if (!(1 <= channel && channel <= 128)) {
     4879      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied");
     4880      return 0;
     4881    }
     4882    if (!(1 <= disknum && disknum <= 15)) {
     4883      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied");
     4884      return 0;
     4885    }
     4886    smart_device * device_found = hpt::helper::find_device(
     4887      this, controller, channel, disknum);
     4888    if (!device_found) {
     4889      return 0;
     4890    }
     4891    return device_found;
     4892  }
     4893
    41804894  return 0;
    41814895}
    41824896
    41834897std::string win_smart_interface::get_valid_custom_dev_types_str()
    41844898{
    4185   return "aacraid,H,L,ID, areca,N[/E]";
     4899  return "aacraid,H,L,ID, areca,N[/E], hpt,L/M/N";
    41864900}
    41874901
    41884902
     
    44235137  }
    44245138
    44255139  // Set valid types
    4426   bool ata, scsi, sat, usb, csmi, nvme;
     5140  bool ata, scsi, sat, usb, csmi, nvme, hpt;
    44275141  if (!type) {
    4428     ata = scsi = usb = sat = csmi = true;
     5142    ata = scsi = usb = sat = csmi = hpt = true;
    44295143#ifdef WITH_NVME_DEVICESCAN // TODO: Remove when NVMe support is no longer EXPERIMENTAL
    44305144    nvme = true;
    44315145#else
     
    44335147#endif
    44345148  }
    44355149  else {
    4436     ata = scsi = usb = sat = csmi = nvme = false;
     5150    ata = scsi = usb = sat = csmi = nvme = hpt = false;
    44375151    if (!strcmp(type, "ata"))
    44385152      ata = true;
    44395153    else if (!strcmp(type, "scsi"))
     
    44465160      csmi = true;
    44475161    else if (!strcmp(type, "nvme"))
    44485162      nvme = true;
     5163    else if (!strcmp(type, "hpt"))
     5164      hpt = true;
    44495165    else {
    44505166      set_err(EINVAL,
    44515167              "Invalid type '%s', valid arguments are: ata[,pd], scsi[,pd], "
    4452               "sat[,pd], usb[,pd], csmi, nvme, pd", type);
     5168              "sat[,pd], usb[,pd], csmi, nvme, pd, hpt[,pd]", type);
    44535169      return false;
    44545170    }
    44555171  }
     
    44565172
    44575173  char name[32];
    44585174
    4459   if (ata || scsi || sat || usb || nvme) {
     5175  if (ata || scsi || sat || usb || nvme || hpt) {
    44605176    // Scan up to 128 drives and 2 3ware controllers
    44615177    const int max_raid = 2;
    44625178    bool raid_seen[max_raid] = {false, false};
     
    45845300      devlist.push_back( new win_nvme_device(this, name, "nvme", 0) );
    45855301    }
    45865302  }
     5303
     5304  if (hpt) {
     5305    hpt::helper::found_device_list list;
     5306    list.reserve(16);
     5307
     5308    hpt::helper::detect_devices(this, list);
     5309
     5310    hpt::helper::found_device_list::iterator iter = list.begin();
     5311
     5312    for (; iter != list.end(); iter++) {
     5313      if (iter->dev_mask & hpt::helper::device_mask::sas) {
     5314        devlist.push_back(
     5315          new win32_highpoint_sas_device(
     5316            this, iter->dev_name, iter->dev_type, iter->scsi_num, iter->device_id)
     5317        );
     5318      }
     5319      else if (iter->dev_mask & hpt::helper::device_mask::ata) {
     5320        devlist.push_back(
     5321          new win32_highpoint_ata_device(
     5322            this, iter->dev_name, iter->dev_type, iter->scsi_num, iter->device_id)
     5323        );
     5324      }
     5325    }
     5326  }
    45875327  return true;
    45885328}
    45895329
  • new file trunk/smartmontools/os_win32/hpt.h

    diff --git a/trunk/smartmontools/os_win32/hpt.h b/trunk/smartmontools/os_win32/hpt.h
    new file mode 10644
    - +  
     1/*
     2 * os_win32/hpt.h
     3 *
     4 * Home page of code is: https://www.smartmontools.org
     5 *
     6 * Copyright (C) 2021 kenjiuno
     7 *
     8 * SPDX-License-Identifier: GPL-2.0-or-later
     9 */
     10
     11#pragma once
     12
     13#define HPT_CTL_CODE(x) CTL_CODE(0x370, 0x900+(x), 0, 0)
     14#define HPT_IOCTL_CODE_GET_VERSION (0)
     15#define HPT_IOCTL_CODE_GET_CHANNEL_INFO (3)
     16#define HPT_IOCTL_CODE_GET_LOGICAL_DEVICES (4)
     17#define HPT_IOCTL_CODE_GET_DEVICE_INFO (5)
     18#define HPT_IOCTL_CODE_IDE_PASS_THROUGH (24)
     19#define HPT_IOCTL_CODE_GET_CONTROLLER_INFO_V2 (47)
     20#define HPT_IOCTL_CODE_GET_PHYSICAL_DEVICES (60)
     21#define HPT_IOCTL_CODE_SCSI_PASS_THROUGH (59)
     22
     23#define HPT_INTERFACE_VERSION 0x02010000
     24
     25#define MAX_ARRAY_MEMBERS_V1 8
     26#define MAX_ARRAYNAME_LEN 16
     27#define MAX_NAME_LENGTH 36
     28
     29#define LDT_ARRAY  1
     30#define LDT_DEVICE 2
     31
     32#define PDT_UNKNOWN  0
     33#define PDT_HARDDISK 1
     34#define PDT_CDROM    2
     35#define PDT_TAPE     3
     36
     37#define AT_UNKNOWN 0
     38#define AT_RAID0   1
     39#define AT_RAID1   2
     40#define AT_RAID5   3
     41#define AT_RAID6   4
     42#define AT_RAID3   5
     43#define AT_RAID4   6
     44#define AT_JBOD    7
     45#define AT_RAID1E  8
     46
     47#define IO_COMMAND_READ  1
     48#define IO_COMMAND_WRITE 2
     49
     50#define DEVICE_FLAG_SATA 0x00000010 /* SATA or SAS device */
     51#define DEVICE_FLAG_SAS  0x00000040 /* SAS device */
     52
     53#pragma pack(push,1)
     54
     55// taken some from vendor header files
     56namespace os_win32::hpt
     57{
     58  typedef struct {
     59    uint32_t seconds:6;      /* 0 - 59 */
     60    uint32_t minutes:6;      /* 0 - 59 */
     61    uint32_t month:4;        /* 1 - 12 */
     62    uint32_t hours:6;        /* 0 - 59 */
     63    uint32_t day:5;          /* 1 - 31 */
     64    uint32_t year:5;         /* 0=2000, 31=2031 */
     65  } TIME_RECORD;
     66
     67  typedef struct {
     68    char name[MAX_ARRAYNAME_LEN];
     69    char description[64];
     70    char create_manager[16];
     71    TIME_RECORD create_time;
     72
     73    uint8_t array_type;
     74    uint8_t block_size_shift;
     75    uint8_t member_count;
     76    uint8_t sub_array_type;
     77
     78    uint32_t flags;
     79    uint32_t members[MAX_ARRAY_MEMBERS_V1];
     80
     81    uint32_t rebuilding_progress;
     82    uint32_t rebuilt_sectors;
     83
     84  } HPT_ARRAY_INFO;
     85
     86  typedef struct {
     87    uint16_t general_configuration;
     88    uint16_t number_of_cylinders;
     89    uint16_t reserved1;
     90    uint16_t number_of_heads;
     91    uint16_t unformatted_bytes_per_track;
     92    uint16_t unformatted_bytes_per_sector;
     93    uint8_t sas_address[8];
     94    uint16_t serial_number[10];
     95    uint16_t buffer_type;
     96    uint16_t buffer_sector_size;
     97    uint16_t number_of_ecc_bytes;
     98    uint16_t firmware_revision[4];
     99    uint16_t model_number[20];
     100    uint8_t maximum_block_transfer;
     101    uint8_t vendor_unique2;
     102    uint16_t double_word_io;
     103    uint16_t capabilities;
     104    uint16_t reserved2;
     105    uint8_t vendor_unique3;
     106    uint8_t pio_cycle_timing_mode;
     107    uint8_t vendor_unique4;
     108    uint8_t dma_cycle_timing_mode;
     109    uint16_t translation_fields_valid;
     110    uint16_t number_of_current_cylinders;
     111    uint16_t number_of_current_heads;
     112    uint16_t current_sectors_per_track;
     113    uint32_t current_sector_capacity;
     114    uint16_t current_multi_sector_setting;
     115    uint32_t user_addressable_sectors;
     116    uint8_t single_word_dmasupport;
     117    uint8_t single_word_dmaactive;
     118    uint8_t multi_word_dmasupport;
     119    uint8_t multi_word_dmaactive;
     120    uint8_t advanced_piomodes;
     121    uint8_t reserved4;
     122    uint16_t minimum_mwxfer_cycle_time;
     123    uint16_t recommended_mwxfer_cycle_time;
     124    uint16_t minimum_piocycle_time;
     125    uint16_t minimum_piocycle_time_iordy;
     126    uint16_t reserved5[2];
     127    uint16_t release_time_overlapped;
     128    uint16_t release_time_service_command;
     129    uint16_t major_revision;
     130    uint16_t minor_revision;
     131   
     132  } IDENTIFY_DATA2;
     133
     134  typedef struct {
     135    uint8_t controller_id;
     136    uint8_t bus_id;
     137    uint8_t target_id;
     138    uint8_t device_mode_setting;
     139    uint8_t device_type;
     140    uint8_t usable_mode;
     141
     142    uint8_t read_ahead_supported: 1;
     143    uint8_t read_ahead_enabled: 1;
     144    uint8_t write_cache_supported: 1;
     145    uint8_t write_cache_enabled: 1;
     146    uint8_t tcq_supported: 1;
     147    uint8_t tcq_enabled: 1;
     148    uint8_t ncq_supported: 1;
     149    uint8_t ncq_enabled: 1;
     150    uint8_t spin_up_mode: 2;
     151    uint8_t reserved6: 6;
     152
     153    uint32_t flags;
     154
     155    IDENTIFY_DATA2 identify_data;
     156
     157  } DEVICE_INFO;
     158
     159  typedef struct {
     160    uint8_t type; // LDT_ARRAY or LDT_DEVICE
     161    uint8_t reserved[3];
     162
     163    uint32_t capacity;
     164    uint32_t parent_array;
     165
     166    union {
     167      HPT_ARRAY_INFO array;
     168      DEVICE_INFO device;
     169    } un;
     170
     171  } LOGICAL_DEVICE_INFO;
     172
     173  typedef struct {
     174    uint8_t chip_type;
     175    uint8_t interrupt_level;
     176    uint8_t num_buses;
     177    uint8_t chip_flags;
     178
     179    uint8_t sz_product_id[MAX_NAME_LENGTH];
     180    uint8_t sz_vendor_id[MAX_NAME_LENGTH];
     181
     182    uint32_t group_id;
     183    uint8_t pci_tree;
     184    uint8_t pci_bus;
     185    uint8_t pci_device;
     186    uint8_t pci_function;
     187
     188    uint32_t ex_flags;
     189  } CONTROLLER_INFO_V2;
     190
     191  typedef struct {
     192    uint32_t id_disk;
     193    uint8_t features_reg;
     194    uint8_t sector_count_reg;
     195    uint8_t lba_low_reg;
     196    uint8_t lba_mid_reg;
     197    uint8_t lba_high_reg;
     198    uint8_t drive_head_reg;
     199    uint8_t command_reg;
     200    uint8_t sectors;
     201    uint8_t protocol;
     202    uint8_t reserve[3];
     203    //uint8_t data_buffer[0];
     204  } IDE_PASS_THROUGH_HEADER;
     205
     206  typedef struct {
     207    uint32_t id_disk;
     208    uint8_t protocol;
     209    uint8_t reserve1;
     210    uint8_t reserve2;
     211    uint8_t cdb_length;
     212    uint8_t cdb[16];
     213    uint32_t data_length;
     214  } SCSI_PASS_THROUGH_IN;
     215
     216  typedef struct {
     217    uint8_t scsi_status;
     218    uint8_t reserve1;
     219    uint8_t reserve2;
     220    uint8_t reserve3;
     221    uint32_t data_length;
     222  } SCSI_PASS_THROUGH_OUT;
     223
     224  typedef struct {
     225    uint32_t io_port;
     226    uint32_t control_port;
     227
     228    uint32_t devices[2];
     229
     230  } CHANNEL_INFO;
     231}
     232
     233// smartmontools specific
     234namespace os_win32::hpt
     235{
     236  typedef struct {
     237    uint32_t in_len;
     238    uint32_t out_len;
     239  } IO_LEN;
     240
     241  typedef struct {
     242    IOCTL_HEADER ioctl_header;
     243    IO_LEN io_len;
     244    // in:
     245    // out:
     246    uint32_t version;
     247
     248  } GET_VERSION_BUFFER;
     249
     250  typedef struct {
     251    IOCTL_HEADER ioctl_header;
     252    IO_LEN io_len; // must: in_len=4, out_len=1028
     253    // in:
     254    uint32_t numIdsToWrite;
     255    // out:
     256    uint32_t numIdsWritten;
     257    uint32_t deviceIds[256];
     258
     259  } GET_PHYSICAL_DEVICES_BUFFER;
     260
     261  typedef struct {
     262    IOCTL_HEADER ioctl_header;
     263    IO_LEN io_len; // must: in_len=4, out_len=1028
     264    // in:
     265    uint32_t numIdsToWrite;
     266    // out:
     267    uint32_t numIdsWritten;
     268    uint32_t deviceIds[256];
     269
     270  } GET_LOGICAL_DEVICES_BUFFER;
     271
     272  typedef struct {
     273    IOCTL_HEADER ioctl_header;
     274    IO_LEN io_len; // must: in_len=4, out_len=174
     275    // in:
     276    uint32_t device_id;
     277    // out:
     278    LOGICAL_DEVICE_INFO out_buf;
     279
     280  } GET_LOGICAL_DEVICE_INFO;
     281
     282  typedef struct {
     283    IOCTL_HEADER ioctl_header;
     284    IO_LEN io_len; // must: in_len=4, out_len=88
     285    // in:
     286    uint32_t controller_id;
     287    // out:
     288    CONTROLLER_INFO_V2 out_buf;
     289
     290  } GET_CONTROLLER_INFO_V2;
     291
     292  typedef struct {
     293    IOCTL_HEADER ioctl_header;
     294    IO_LEN io_len; // must: in_len=8, out_len=16
     295    // in:
     296    uint32_t controller_id;
     297    uint32_t bus_num;
     298    // out:
     299    CHANNEL_INFO out_buf;
     300
     301  } GET_CHANNEL_INFO;
     302
     303}
     304
     305#pragma pack(pop)