| 3901 | |
| 3902 | ////////////////////////////////////////////////////////////////////// |
| 3903 | // win32_highpoint_common |
| 3904 | |
| 3905 | class win32_highpoint_common |
| 3906 | : virtual public /*extends*/ win_smart_device |
| 3907 | { |
| 3908 | public: |
| 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 | |
| 3945 | protected: |
| 3946 | |
| 3947 | }; |
| 3948 | |
| 3949 | bool 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 | |
| 3979 | bool 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 | |
| 4020 | bool 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 | |
| 4035 | bool 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 | |
| 4054 | bool 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 | |
| 4073 | bool 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 | |
| 4089 | bool 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 | |
| 4105 | bool 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 | |
| 4125 | class win32_highpoint_ata_device |
| 4126 | : public /*implements*/ ata_device, |
| 4127 | public /*extends*/ win32_highpoint_common |
| 4128 | { |
| 4129 | public: |
| 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 | |
| 4135 | protected: |
| 4136 | virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); |
| 4137 | |
| 4138 | private: |
| 4139 | unsigned int m_scsi_num; |
| 4140 | unsigned int m_device_id; |
| 4141 | }; |
| 4142 | |
| 4143 | win32_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 | |
| 4152 | bool 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 | |
| 4166 | bool 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 | |
| 4249 | class win32_highpoint_sas_device |
| 4250 | : public /*implements*/ scsi_device, |
| 4251 | public /*extends*/ win32_highpoint_common |
| 4252 | { |
| 4253 | public: |
| 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 | |
| 4259 | protected: |
| 4260 | virtual bool scsi_pass_through(struct scsi_cmnd_io *iop); |
| 4261 | |
| 4262 | private: |
| 4263 | unsigned int m_scsi_num; |
| 4264 | unsigned int m_device_id; |
| 4265 | }; |
| 4266 | |
| 4267 | win32_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 | |
| 4276 | bool 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 | |
| 4290 | bool 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 | |
| 4363 | namespace 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 | |