Ticket #645: 20211022-1556.patch

File 20211022-1556.patch, 30.8 KB (added by kenjiuno, 4 years ago)

win32 HighPoint? RocketRAID support (adding comments and removed some redundants)

  • Makefile.am

     
    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 \
  • os_win32.cpp

     
    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  /**
     3914   * Send a HPT HBA specific IOCTL_SCSI_MINIPORT ioctl request to this device.
     3915   *
     3916   * @param code HPT_CTL_CODE. e.g. `HPT_IOCTL_CODE_GET_VERSION`
     3917   * @param ioctl_buffer entire buffer supplied to DeviceIoControl API
     3918   * @param ioctl_bufsiz entire buffer length
     3919   */
     3920  bool hpt_ioctl(unsigned code, IOCTL_HEADER * ioctl_buffer,
     3921    unsigned ioctl_bufsiz);
     3922
     3923  /**
     3924   * Query interface version to the device.
     3925   *
     3926   * version:
     3927   *
     3928   * - `0` if HPT HBA is not present.
     3929   * - `0x02010000` means version `2.1`.
     3930   *
     3931   * @param [out] version 0x02010000 or such.
     3932   */
     3933  bool get_version(uint32_t & version);
     3934
     3935  /**
     3936   * Open scsi device.
     3937   *
     3938   * @param n N of `\\.\ScsiN:`
     3939   */
     3940  bool open_scsi(int n);
     3941
     3942  /**
     3943   * Query one device (either physical or array) info.
     3944   *
     3945   * @param device_id device id allocated by HBA
     3946   * @param out_buf info
     3947   */
     3948  bool get_device_info(uint32_t device_id, hpt::LOGICAL_DEVICE_INFO * out_buf);
     3949
     3950  /**
     3951   * Query one controller info.
     3952   *
     3953   * @param controller_id local controller number (1, 2, 3, ...)
     3954   * @param out_buf info
     3955   */
     3956  bool get_controller_info_v2(uint32_t controller_id, hpt::CONTROLLER_INFO_V2 * out_buf);
     3957
     3958  /**
     3959   * Query one channel info.
     3960   *
     3961   * @param controller_id local controller number (1, 2, 3, ...)
     3962   * @param bus_num channel number (1, 2, 3, ...)
     3963   * @param out_buf info
     3964   */
     3965  bool get_channel_info(uint32_t controller_id, uint32_t bus_num, hpt::CHANNEL_INFO * out_buf);
     3966
     3967protected:
     3968
     3969};
     3970
     3971bool win32_highpoint_common::open_scsi(int n)
     3972{
     3973  // TODO: Use common open function for all devices using "\\.\ScsiN:"
     3974  char devpath[32];
     3975  snprintf(devpath, sizeof(devpath)-1, "\\\\.\\Scsi%d:", n);
     3976
     3977  HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
     3978    FILE_SHARE_READ|FILE_SHARE_WRITE,
     3979    (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, 0);
     3980
     3981  if (h == INVALID_HANDLE_VALUE) {
     3982    long err = GetLastError();
     3983    if (scsi_debugmode > 1)
     3984      pout("  %s: Open failed, Error=%ld\n", devpath, err);
     3985    if (err == ERROR_FILE_NOT_FOUND)
     3986      set_err(ENOENT, "%s: not found", devpath);
     3987    else if (err == ERROR_ACCESS_DENIED)
     3988      set_err(EACCES, "%s: access denied", devpath);
     3989    else
     3990      set_err(EIO, "%s: Error=%ld", devpath, err);
     3991    return false;
     3992  }
     3993
     3994  if (scsi_debugmode > 1)
     3995    pout("  %s: successfully opened\n", devpath);
     3996
     3997  set_fh(h);
     3998  return true; 
     3999}
     4000
     4001bool win32_highpoint_common::hpt_ioctl(unsigned code, IOCTL_HEADER * ioctl_buffer,
     4002  unsigned ioctl_bufsiz)
     4003{
     4004  // Set header
     4005  ioctl_buffer->HeaderLength = sizeof(IOCTL_HEADER);
     4006  memcpy((char *)ioctl_buffer->Signature, "HPT-CTRL\0", sizeof(ioctl_buffer->Signature));
     4007  ioctl_buffer->Timeout = CSMI_SAS_TIMEOUT;
     4008  ioctl_buffer->ControlCode = HPT_CTL_CODE(code);
     4009  ioctl_buffer->ReturnCode = 0;
     4010  ioctl_buffer->Length = ioctl_bufsiz - sizeof(IOCTL_HEADER);
     4011
     4012  // Call function
     4013  DWORD num_out = 0;
     4014  if (!DeviceIoControl(get_fh(), IOCTL_SCSI_MINIPORT,
     4015    ioctl_buffer, ioctl_bufsiz, ioctl_buffer, ioctl_bufsiz, &num_out, (OVERLAPPED*)0)) {
     4016    long err = GetLastError();
     4017    if (scsi_debugmode)
     4018      pout("  IOCTL_SCSI_MINIPORT(HPT_CTL_CODE_%u) failed, Error=%ld\n", code, err);
     4019    if (   err == ERROR_INVALID_FUNCTION
     4020        || err == ERROR_NOT_SUPPORTED
     4021        || err == ERROR_DEV_NOT_EXIST)
     4022      return set_err(ENOSYS, "HPT command is not supported (Error=%ld)", err);
     4023    else
     4024      return set_err(EIO, "HPT command(%u) failed with Error=%ld", code, err);
     4025  }
     4026
     4027  // Check result
     4028  if (ioctl_buffer->ReturnCode) {
     4029    if (scsi_debugmode) {
     4030      pout("  IOCTL_SCSI_MINIPORT(HPT_CTL_CODE_%u) failed, ReturnCode=%u\n",
     4031        code, (unsigned)ioctl_buffer->ReturnCode);
     4032    }
     4033    return set_err(EIO, "HPT command(%u) failed with ReturnCode=%u", code, (unsigned)ioctl_buffer->ReturnCode);
     4034  }
     4035
     4036  if (scsi_debugmode > 1)
     4037    pout("  IOCTL_SCSI_MINIPORT(HPT_CTL_CODE_%u) succeeded, bytes returned: %u\n", code, (unsigned)num_out);
     4038
     4039  return true;
     4040}
     4041
     4042bool win32_highpoint_common::get_version(uint32_t & version)
     4043{
     4044  hpt::buffer_layouter buf(0, 4);
     4045
     4046  if (!hpt_ioctl(HPT_IOCTL_CODE_GET_VERSION, buf.ioctl_header(), buf.total_size())) {
     4047    return false;
     4048  }
     4049
     4050  typedef struct {
     4051    uint32_t version;
     4052  } out_format;
     4053
     4054  version = reinterpret_cast<out_format *>(buf.out_data())->version;
     4055  return true;
     4056}
     4057
     4058bool win32_highpoint_common::get_device_info(uint32_t device_id, hpt::LOGICAL_DEVICE_INFO * out_buf)
     4059{
     4060  hpt::buffer_layouter buf(4, sizeof(hpt::LOGICAL_DEVICE_INFO));
     4061
     4062  typedef struct {
     4063    uint32_t device_id;
     4064  } in_format;
     4065
     4066  reinterpret_cast<in_format *>(buf.in_data())->device_id = device_id;
     4067
     4068  if (!hpt_ioctl(HPT_IOCTL_CODE_GET_DEVICE_INFO, buf.ioctl_header(), buf.total_size())) {
     4069    return false;
     4070  }
     4071
     4072  memcpy(out_buf, buf.out_data(), sizeof(hpt::LOGICAL_DEVICE_INFO));
     4073  return true;
     4074}
     4075
     4076bool win32_highpoint_common::get_controller_info_v2(uint32_t controller_id, hpt::CONTROLLER_INFO_V2 * out_buf)
     4077{
     4078  hpt::buffer_layouter buf(4, sizeof(hpt::CONTROLLER_INFO_V2));
     4079
     4080  typedef struct {
     4081    uint32_t controller_id;
     4082  } in_format;
     4083
     4084  reinterpret_cast<in_format *>(buf.in_data())->controller_id = controller_id - 1;
     4085
     4086  if (!hpt_ioctl(HPT_IOCTL_CODE_GET_CONTROLLER_INFO_V2, buf.ioctl_header(), buf.total_size())) {
     4087    return false;
     4088  }
     4089
     4090  memcpy(out_buf, buf.out_data(), sizeof(hpt::CONTROLLER_INFO_V2));
     4091  return true;
     4092}
     4093
     4094bool win32_highpoint_common::get_channel_info(uint32_t controller_id, uint32_t bus_num,
     4095  hpt::CHANNEL_INFO * out_buf)
     4096{
     4097  hpt::buffer_layouter buf(8, sizeof(hpt::CHANNEL_INFO));
     4098
     4099#pragma pack(push,1)
     4100  typedef struct {
     4101    uint32_t controller_id;
     4102    uint32_t bus_num;
     4103  } in_format;
     4104#pragma pack(pop)
     4105
     4106  reinterpret_cast<in_format *>(buf.in_data())->controller_id = controller_id - 1;
     4107  reinterpret_cast<in_format *>(buf.in_data())->bus_num = bus_num - 1;
     4108
     4109  if (!hpt_ioctl(HPT_IOCTL_CODE_GET_CHANNEL_INFO, buf.ioctl_header(), buf.total_size())) {
     4110    return false;
     4111  }
     4112
     4113  memcpy(out_buf, buf.out_data(), sizeof(hpt::CHANNEL_INFO));
     4114  return true;
     4115}
     4116
     4117//////////////////////////////////////////////////////////////////////
     4118// win32_highpoint_ata_device
     4119
     4120class win32_highpoint_ata_device
     4121: public /*implements*/ ata_device,
     4122  public /*extends*/ win32_highpoint_common
     4123{
     4124public:
     4125  win32_highpoint_ata_device(smart_interface * intf,
     4126    const char * dev_name, const char * dev_type, unsigned int scsi_num, unsigned int device_id);
     4127
     4128  virtual bool open() override;
     4129
     4130  /**
     4131   * Send a HPT_IOCTL_IDE_PASS_THROUGH request.
     4132   */
     4133  virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
     4134 
     4135private:
     4136  unsigned int m_scsi_num;
     4137  unsigned int m_device_id;
     4138};
     4139
     4140win32_highpoint_ata_device::win32_highpoint_ata_device(smart_interface * intf,
     4141  const char * dev_name, const char * dev_type, unsigned int scsi_num, unsigned int device_id)
     4142: smart_device(intf, dev_name, dev_type, "")
     4143{
     4144  m_scsi_num = scsi_num;
     4145  m_device_id = device_id;
     4146  set_info().info_name = strprintf("%s", dev_name);
     4147}
     4148
     4149bool win32_highpoint_ata_device::open()
     4150{
     4151  if (!open_scsi(m_scsi_num))
     4152    return false;
     4153
     4154  uint32_t ver;
     4155  if (!get_version(ver)) {
     4156    close();
     4157    return false;
     4158  }
     4159
     4160  return true;
     4161}
     4162
     4163bool win32_highpoint_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
     4164{
     4165  const bool will_read = in.direction == ata_cmd_in::data_in;
     4166  const bool will_write = in.direction == ata_cmd_in::data_out;
     4167
     4168  const size_t bytes_in_data = will_write ? in.size : 0;
     4169  const size_t bytes_out_data = will_read ? in.size : 0;
     4170
     4171  hpt::buffer_layouter blk(
     4172    sizeof(hpt::IDE_PASS_THROUGH_HEADER) + bytes_in_data,
     4173    sizeof(hpt::IDE_PASS_THROUGH_HEADER) + bytes_out_data
     4174  );
     4175
     4176  if (!blk.allocated()) {
     4177    return smart_device::set_err(ENOMEM, "buffer allocation failure");
     4178  }
     4179
     4180  hpt::IDE_PASS_THROUGH_HEADER * ata_in = reinterpret_cast<hpt::IDE_PASS_THROUGH_HEADER *>(blk.in_data());
     4181
     4182  void *user_data_in = &ata_in[1];
     4183
     4184  hpt::IDE_PASS_THROUGH_HEADER * ata_out = reinterpret_cast<hpt::IDE_PASS_THROUGH_HEADER *>(blk.out_data());
     4185
     4186  void *user_data_out = &ata_out[1];
     4187 
     4188  ata_in->id_disk = m_device_id;
     4189  ata_in->features_reg = in.in_regs.features;
     4190  ata_in->sector_count_reg = in.in_regs.sector_count;
     4191  ata_in->lba_low_reg = in.in_regs.lba_low;
     4192  ata_in->lba_mid_reg = in.in_regs.lba_mid;
     4193  ata_in->lba_high_reg = in.in_regs.lba_high;
     4194  ata_in->drive_head_reg = in.in_regs.device;
     4195  ata_in->command_reg = in.in_regs.command;
     4196  ata_in->sectors = in.in_regs.sector_count;
     4197  ata_in->protocol =
     4198    will_read ? IO_COMMAND_READ :
     4199    will_write ? IO_COMMAND_WRITE :
     4200    0;
     4201 
     4202  memcpy(user_data_in, in.buffer, bytes_in_data);
     4203 
     4204  if (!hpt_ioctl(HPT_IOCTL_CODE_IDE_PASS_THROUGH, blk.ioctl_header(), blk.total_size())) {
     4205    return false;
     4206  }
     4207 
     4208  ata_out_regs_48bit &r = out.out_regs;
     4209  r.error           = ata_out->features_reg;
     4210  r.sector_count_16 = ata_out->sector_count_reg;
     4211  r.lba_low_16      = ata_out->lba_low_reg;
     4212  r.lba_mid_16      = ata_out->lba_mid_reg;
     4213  r.lba_high_16     = ata_out->lba_high_reg;
     4214  r.device          = ata_out->drive_head_reg;
     4215  r.status          = ata_out->command_reg;
     4216
     4217  memcpy(in.buffer, user_data_out, bytes_out_data);
     4218
     4219  return true;
     4220}
     4221
     4222//////////////////////////////////////////////////////////////////////
     4223// win32_highpoint_sas_device
     4224
     4225class win32_highpoint_sas_device
     4226: public /*implements*/ scsi_device,
     4227  public /*extends*/ win32_highpoint_common
     4228{
     4229public:
     4230  win32_highpoint_sas_device(smart_interface * intf,
     4231    const char * dev_name, const char * dev_type , unsigned int scsi_num, unsigned int device_id);
     4232
     4233  virtual bool open() override;
     4234
     4235  /**
     4236   * Send a HPT_IOCTL_SCSI_PASS_THROUGH request.
     4237   */
     4238  virtual bool scsi_pass_through(struct scsi_cmnd_io *iop);
     4239
     4240private:
     4241  unsigned int m_scsi_num;
     4242  unsigned int m_device_id;
     4243};
     4244
     4245win32_highpoint_sas_device::win32_highpoint_sas_device(smart_interface * intf,
     4246  const char * dev_name, const char * dev_type, unsigned int scsi_num, unsigned int device_id)
     4247: smart_device(intf, dev_name, dev_type, "")
     4248{
     4249  m_scsi_num = scsi_num;
     4250  m_device_id = device_id;
     4251  set_info().info_name = strprintf("%s", dev_name);
     4252}
     4253
     4254bool win32_highpoint_sas_device::open()
     4255{
     4256  if (!open_scsi(m_scsi_num))
     4257    return false;
     4258
     4259  uint32_t ver;
     4260  if (!get_version(ver)) {
     4261    close();
     4262    return false;
     4263  }
     4264
     4265  return true;
     4266}
     4267
     4268bool win32_highpoint_sas_device::scsi_pass_through(struct scsi_cmnd_io *iop)
     4269{
     4270  const bool will_read = iop->dxfer_dir == DXFER_FROM_DEVICE;
     4271  const bool will_write = iop->dxfer_dir == DXFER_TO_DEVICE;
     4272 
     4273  const size_t bytes_in_data = will_write?iop->dxfer_len:0;
     4274  const size_t bytes_out_data = will_read?iop->dxfer_len:0;
     4275 
     4276  hpt::buffer_layouter blk(
     4277    sizeof(hpt::SCSI_PASS_THROUGH_IN) + bytes_in_data,
     4278    sizeof(hpt::SCSI_PASS_THROUGH_OUT) + bytes_out_data
     4279  );
     4280
     4281  if (!blk.allocated()) {
     4282    return smart_device::set_err(ENOMEM, "buffer allocation failure");
     4283  }
     4284
     4285  hpt::SCSI_PASS_THROUGH_IN * scsi_in = reinterpret_cast<hpt::SCSI_PASS_THROUGH_IN *>(blk.in_data());
     4286
     4287  void *user_data_in = &scsi_in[1];
     4288
     4289  hpt::SCSI_PASS_THROUGH_OUT * scsi_out = reinterpret_cast<hpt::SCSI_PASS_THROUGH_OUT *>(blk.out_data());
     4290
     4291  void *user_data_out = &scsi_out[1];
     4292 
     4293  scsi_in->id_disk = m_device_id;
     4294  scsi_in->protocol =
     4295    will_read ? IO_COMMAND_READ :
     4296    will_write ? IO_COMMAND_WRITE :
     4297    0;
     4298  scsi_in->cdb_length = iop->cmnd_len;
     4299  memcpy(scsi_in->cdb, iop->cmnd, iop->cmnd_len);
     4300  scsi_in->data_length = iop->dxfer_len;
     4301 
     4302  memcpy(user_data_in, iop->dxferp, bytes_in_data);
     4303
     4304  if (!hpt_ioctl(HPT_IOCTL_CODE_SCSI_PASS_THROUGH, blk.ioctl_header(), blk.total_size())) {
     4305    return false;
     4306  }
     4307
     4308  memcpy(iop->dxferp, user_data_out, bytes_out_data);
     4309   
     4310  iop->scsi_status = scsi_out->scsi_status;
     4311  iop->resp_sense_len = scsi_out->data_length;
     4312  iop->resid = 0;
     4313 
     4314  return true;
     4315}
     4316
     4317//////////////////////////////////////////////////////////////////////
     4318// hpt::helper
     4319
     4320namespace hpt::helper
     4321{
     4322  typedef enum {
     4323    ata = 0x01,
     4324    sas = 0x02,
     4325    array = 0x04,
     4326
     4327    harddisk = 0x10,
     4328    cdrom = 0x20,
     4329    tape = 0x30,
     4330
     4331    raid0 = 0x0100,
     4332    raid1 = 0x0200,
     4333    raid5 = 0x0300,
     4334    raid6 = 0x0400,
     4335    raid3 = 0x0500,
     4336    raid4 = 0x0600,
     4337    jbod = 0x0700,
     4338    raid1e = 0x0800,
     4339  } device_mask;
     4340
     4341  typedef struct {
     4342    uint32_t cross_hba_controller_id;
     4343
     4344    uint32_t controller_id;
     4345    uint32_t channel;
     4346    uint32_t disknum;
     4347
     4348    uint32_t scsi_num;
     4349    uint32_t device_id;
     4350
     4351    uint32_t dev_mask;
     4352
     4353    char dev_name[16]; // "/dev/scsi0c1"
     4354    char dev_type[16]; // "hpt,L/M/N"
     4355  } found_device;
     4356
     4357  typedef std::vector<found_device> found_device_list;
     4358
     4359  void detect_devices(
     4360    smart_interface * intf,
     4361    found_device_list & out_list
     4362  )
     4363  {
     4364    uint32_t cross_hba_controller_id = 1;
     4365
     4366    for (uint32_t scsi_num = 0; ; scsi_num++) {
     4367      win32_highpoint_ata_device test_dev(intf, "", "", scsi_num, 0);
     4368      if (!test_dev.open()) {
     4369        if (test_dev.get_errno() == ENOENT) {
     4370          break;
     4371        }
     4372        else {
     4373          if (scsi_debugmode > 1) {
     4374            pout("  hpt: scsi_num %u is not a RocketRAID HBA\n", scsi_num);
     4375          }
     4376          continue;
     4377        }
     4378      }
     4379     
     4380      for (uint32_t controller_id = 1; ; controller_id++, cross_hba_controller_id++) {
     4381        CONTROLLER_INFO_V2 ctrl_info;
     4382        if (!test_dev.get_controller_info_v2(controller_id, &ctrl_info)) {
     4383          if (scsi_debugmode > 1) {
     4384            pout("  hpt: scsi_num %u controller_id %u is not available\n", scsi_num, controller_id);
     4385          }
     4386          break;
     4387        }
     4388
     4389        for (uint32_t channel = 1; ; channel++) {
     4390          CHANNEL_INFO chan_info;
     4391          if (!test_dev.get_channel_info(controller_id, channel, &chan_info)) {
     4392            if (scsi_debugmode > 1) {
     4393              pout("  hpt: scsi_num %u controller_id %u channel %u is not available\n"
     4394                , scsi_num, controller_id, channel);
     4395            }
     4396            break;
     4397          }
     4398
     4399          for (uint32_t disknum = 1; disknum <= 2; disknum++) {
     4400            const uint32_t device_id = chan_info.devices[disknum - 1];
     4401            if (device_id == 0) {
     4402              // no device is connected.
     4403              continue;
     4404            }
     4405
     4406            LOGICAL_DEVICE_INFO dev_info;
     4407            if (!test_dev.get_device_info(device_id, &dev_info)) {
     4408              continue;
     4409            }
     4410
     4411            found_device found;
     4412            found.cross_hba_controller_id = cross_hba_controller_id;
     4413
     4414            found.controller_id = controller_id;
     4415            found.channel = channel;
     4416            found.disknum = disknum;
     4417
     4418            found.scsi_num = scsi_num;
     4419            found.device_id = device_id;
     4420
     4421            found.dev_mask = 0;
     4422
     4423            snprintf(found.dev_name, sizeof(found.dev_name)
     4424              , "/dev/scsi%ud%u"
     4425              , scsi_num, device_id);
     4426
     4427            snprintf(found.dev_type, sizeof(found.dev_type)
     4428              , "hpt,%u/%u/%u"
     4429              , cross_hba_controller_id, channel, disknum);
     4430
     4431            switch (dev_info.type) {
     4432              case LDT_DEVICE:
     4433                {
     4434                  // sata device: DEVICE_FLAG_SATA
     4435                  // sas device:  DEVICE_FLAG_SATA|DEVICE_FLAG_SAS
     4436
     4437                  if (dev_info.un.device.flags & DEVICE_FLAG_SAS) {
     4438                    found.dev_mask |= device_mask::sas;
     4439                  }
     4440                  else if (dev_info.un.device.flags & DEVICE_FLAG_SATA) {
     4441                    found.dev_mask |= device_mask::ata;
     4442                  }
     4443
     4444                  found.dev_mask |= (dev_info.un.device.device_type & 0xF) << 4; // PDT_HARDDISK and so on.
     4445                  break;
     4446                }
     4447              case LDT_ARRAY:
     4448                {
     4449                  found.dev_mask |= device_mask::array;
     4450
     4451                  found.dev_mask |= (dev_info.un.array.array_type & 0xFF) << 8; // AT_RAID0 and so on.
     4452                  break;
     4453                }
     4454            }
     4455
     4456            out_list.push_back(found);
     4457
     4458            if (scsi_debugmode > 1) {
     4459              std::string desc = "unknown device";
     4460              {
     4461                if (found.dev_mask & device_mask::sas) {
     4462                  desc = "sas";
     4463                }
     4464                else if (found.dev_mask & device_mask::ata) {
     4465                  desc = "ata";
     4466                }
     4467                else if (found.dev_mask & device_mask::array) {
     4468                  if (found.dev_mask & raid0) desc += "raid0";
     4469                  if (found.dev_mask & raid1) desc += "raid1";
     4470                  if (found.dev_mask & raid5) desc += "raid5";
     4471                  if (found.dev_mask & raid6) desc += "raid6";
     4472                  if (found.dev_mask & raid3) desc += "raid3";
     4473                  if (found.dev_mask & raid4) desc += "raid4";
     4474                  if (found.dev_mask & jbod) desc += "jbod";
     4475                  if (found.dev_mask & raid1e) desc += "raid1e";
     4476                  else desc += "unknown";
     4477
     4478                  desc += " array";
     4479                }
     4480                else {
     4481                  desc = "unknown";
     4482                }
     4483
     4484                if (found.dev_mask & device_mask::harddisk) desc += " harddisk";
     4485                else if (found.dev_mask & device_mask::cdrom) desc += " cdrom";
     4486                else if (found.dev_mask & device_mask::tape) desc += " tape";
     4487                else desc = "unknown";
     4488
     4489                desc += " device";
     4490              }
     4491
     4492              pout("  hpt: %s found hpt,%u/%u/%u (scsi_num %u device_id %u device_mask %08x)\n"
     4493                , desc.c_str()
     4494                , cross_hba_controller_id, channel, disknum
     4495                , scsi_num, device_id, found.dev_mask
     4496              );
     4497            }
     4498
     4499          }
     4500        }
     4501      }
     4502    }
     4503  }
     4504
     4505  smart_device * find_device(
     4506    smart_interface * intf,
     4507    const uint32_t controller,
     4508    const uint32_t channel,
     4509    const uint32_t disknum
     4510  )
     4511  {
     4512    found_device_list list;
     4513    list.reserve(16);
     4514
     4515    detect_devices(intf, list);
     4516
     4517    found_device_list::iterator iter = list.begin();
     4518    for (; iter != list.end(); iter++) {
     4519      if (true
     4520        && iter->cross_hba_controller_id == controller
     4521        && iter->channel == channel
     4522        && iter->disknum == disknum
     4523      )
     4524      {
     4525        if (iter->dev_mask & device_mask::sas) {
     4526          return new win32_highpoint_sas_device(intf,
     4527            iter->dev_name, iter->dev_type, iter->scsi_num, iter->device_id);
     4528        }
     4529        else if (iter->dev_mask & device_mask::ata) {
     4530          return new win32_highpoint_ata_device(intf,
     4531            iter->dev_name, iter->dev_type, iter->scsi_num, iter->device_id);
     4532        }
     4533        return nullptr;
     4534      }
     4535    }
     4536    return nullptr;
     4537  }
     4538}
     4539
    38984540/////////////////////////////////////////////////////////////////////////////
    38994541// win_smart_interface
    39004542// Platform specific interface
     
    41774819    return 0;
    41784820  }
    41794821
     4822  // Highpoint ?
     4823  int controller = -1, channel = -1; disknum = 1;
     4824  n1 = n2 = -1; int n3 = -1;
     4825  if (sscanf(type, "hpt,%n%d/%d%n/%d%n", &n1, &controller, &channel, &n2, &disknum, &n3) >= 2 || n1 == 4) {
     4826    int len = strlen(type);
     4827    if (!(n2 == len || n3 == len)) {
     4828      set_err(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items");
     4829      return 0;
     4830    }
     4831    if (!(1 <= controller && controller <= 8)) {
     4832      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied");
     4833      return 0;
     4834    }
     4835    if (!(1 <= channel && channel <= 128)) {
     4836      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied");
     4837      return 0;
     4838    }
     4839    if (!(1 <= disknum && disknum <= 15)) {
     4840      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied");
     4841      return 0;
     4842    }
     4843    smart_device * device_found = hpt::helper::find_device(
     4844      this, controller, channel, disknum);
     4845    if (!device_found) {
     4846      return 0;
     4847    }
     4848    return device_found;
     4849  }
     4850
    41804851  return 0;
    41814852}
    41824853
    41834854std::string win_smart_interface::get_valid_custom_dev_types_str()
    41844855{
    4185   return "aacraid,H,L,ID, areca,N[/E]";
     4856  return "aacraid,H,L,ID, areca,N[/E], hpt,L/M/N";
    41864857}
    41874858
    41884859
     
    44235094  }
    44245095
    44255096  // Set valid types
    4426   bool ata, scsi, sat, usb, csmi, nvme;
     5097  bool ata, scsi, sat, usb, csmi, nvme, hpt;
    44275098  if (!type) {
    4428     ata = scsi = usb = sat = csmi = true;
     5099    ata = scsi = usb = sat = csmi = hpt = true;
    44295100#ifdef WITH_NVME_DEVICESCAN // TODO: Remove when NVMe support is no longer EXPERIMENTAL
    44305101    nvme = true;
    44315102#else
     
    44335104#endif
    44345105  }
    44355106  else {
    4436     ata = scsi = usb = sat = csmi = nvme = false;
     5107    ata = scsi = usb = sat = csmi = nvme = hpt = false;
    44375108    if (!strcmp(type, "ata"))
    44385109      ata = true;
    44395110    else if (!strcmp(type, "scsi"))
     
    44465117      csmi = true;
    44475118    else if (!strcmp(type, "nvme"))
    44485119      nvme = true;
     5120    else if (!strcmp(type, "hpt"))
     5121      hpt = true;
    44495122    else {
    44505123      set_err(EINVAL,
    44515124              "Invalid type '%s', valid arguments are: ata[,pd], scsi[,pd], "
    4452               "sat[,pd], usb[,pd], csmi, nvme, pd", type);
     5125              "sat[,pd], usb[,pd], csmi, nvme, pd, hpt[,pd]", type);
    44535126      return false;
    44545127    }
    44555128  }
     
    44565129
    44575130  char name[32];
    44585131
    4459   if (ata || scsi || sat || usb || nvme) {
     5132  if (ata || scsi || sat || usb || nvme || hpt) {
    44605133    // Scan up to 128 drives and 2 3ware controllers
    44615134    const int max_raid = 2;
    44625135    bool raid_seen[max_raid] = {false, false};
     
    45845257      devlist.push_back( new win_nvme_device(this, name, "nvme", 0) );
    45855258    }
    45865259  }
     5260
     5261  if (hpt) {
     5262    hpt::helper::found_device_list list;
     5263    list.reserve(16);
     5264
     5265    hpt::helper::detect_devices(this, list);
     5266
     5267    hpt::helper::found_device_list::iterator iter = list.begin();
     5268
     5269    for (; iter != list.end(); iter++) {
     5270      if (iter->dev_mask & hpt::helper::device_mask::sas) {
     5271        devlist.push_back(
     5272          new win32_highpoint_sas_device(
     5273            this, iter->dev_name, iter->dev_type, iter->scsi_num, iter->device_id)
     5274        );
     5275      }
     5276      else if (iter->dev_mask & hpt::helper::device_mask::ata) {
     5277        devlist.push_back(
     5278          new win32_highpoint_ata_device(
     5279            this, iter->dev_name, iter->dev_type, iter->scsi_num, iter->device_id)
     5280        );
     5281      }
     5282    }
     5283  }
    45875284  return true;
    45885285}
    45895286
  • os_win32/hpt.h

     
     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  /**
     242   * Represents a buffer layout suitable for HPT HBA `IOCTL_SCSI_MINIPORT` ioctl request.
     243   *
     244   * Layout:
     245   *
     246   * 1. `IOCTL_HEADER`
     247   * 2. `IO_LEN`
     248   * 3. input data (written by user)
     249   * 4. output data (written by driver)
     250   *
     251   * The actual data format is decided by `IOCTL_HEADER.ControlCode`.
     252   */
     253  class buffer_layouter {
     254  public:
     255    buffer_layouter(unsigned in_len, unsigned out_len)
     256    : m_blk(sizeof(IOCTL_HEADER) + sizeof(IO_LEN) + in_len + out_len)
     257    , m_io_len(nullptr)
     258    , m_in_data(nullptr)
     259    , m_out_data(nullptr)
     260    {
     261      unsigned char * buf = m_blk.data();
     262      if (buf) {
     263        m_io_len = reinterpret_cast<IO_LEN *>(buf + sizeof(IOCTL_HEADER));
     264        m_in_data = buf + sizeof(IOCTL_HEADER) + sizeof(IO_LEN);
     265        m_out_data = buf + sizeof(IOCTL_HEADER) + sizeof(IO_LEN) + in_len;
     266
     267        m_io_len->in_len = in_len;
     268        m_io_len->out_len = out_len;
     269      }
     270    }
     271
     272    bool allocated() const { return m_blk.data() != nullptr; }
     273    IOCTL_HEADER * ioctl_header() { return reinterpret_cast<IOCTL_HEADER *>(m_blk.data()); }
     274    IO_LEN * io_len() { return m_io_len; }
     275    void * in_data() { return m_in_data; }
     276    void * out_data() { return m_out_data; }
     277    unsigned total_size() const { return m_blk.size(); }
     278
     279  private:
     280    raw_buffer m_blk;
     281    IO_LEN * m_io_len;
     282    void * m_in_data;
     283    void * m_out_data;
     284
     285    buffer_layouter(const buffer_layouter &);
     286    void operator =(const buffer_layouter &);
     287  };
     288
     289}
     290
     291#pragma pack(pop)