| 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 | /** |
| 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 | |
| 3967 | protected: |
| 3968 | |
| 3969 | }; |
| 3970 | |
| 3971 | bool 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 | |
| 4001 | bool 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 | |
| 4042 | bool 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 | |
| 4058 | bool 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 | |
| 4076 | bool 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 | |
| 4094 | bool 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 | |
| 4120 | class win32_highpoint_ata_device |
| 4121 | : public /*implements*/ ata_device, |
| 4122 | public /*extends*/ win32_highpoint_common |
| 4123 | { |
| 4124 | public: |
| 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 | |
| 4135 | private: |
| 4136 | unsigned int m_scsi_num; |
| 4137 | unsigned int m_device_id; |
| 4138 | }; |
| 4139 | |
| 4140 | win32_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 | |
| 4149 | bool 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 | |
| 4163 | bool 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 | |
| 4225 | class win32_highpoint_sas_device |
| 4226 | : public /*implements*/ scsi_device, |
| 4227 | public /*extends*/ win32_highpoint_common |
| 4228 | { |
| 4229 | public: |
| 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 | |
| 4240 | private: |
| 4241 | unsigned int m_scsi_num; |
| 4242 | unsigned int m_device_id; |
| 4243 | }; |
| 4244 | |
| 4245 | win32_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 | |
| 4254 | bool 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 | |
| 4268 | bool 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 | |
| 4320 | namespace 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 | |