Opened 22 months ago
Last modified 21 months ago
#1685 new enhancement
Support for HighPoint controller with EJ340 extender
Reported by: | PsychOsmosis | Owned by: | |
---|---|---|---|
Priority: | minor | Milestone: | undecided |
Component: | all | Version: | |
Keywords: | highpoint linux freebsd | Cc: |
Description
The drives connected to my HighPoint RR4520 along with EJ340 extenders are numbered using the 1/E1/1 format (there's always an "E" before the second number). The smartctl command (using the "hpt" parameter) reject my inputs as it expects numbers only (ie. 1/1/1).
I would very much appreciate if the command could be fixed so it accepts the "E" in the drive numbering format of my hardware.
Thanks in advance!
Change History (18)
comment:1 by , 22 months ago
Component: | all → smartctl |
---|
comment:2 by , 22 months ago
Component: | smartctl → all |
---|---|
Keywords: | highpoint added |
Milestone: | → undecided |
Type: | defect → enhancement |
comment:3 by , 22 months ago
Keywords: | linux freebsd added |
---|---|
Summary: | HighPoint smartctl invalid format → Support for HighPoint controller with EJ340 extender |
comment:4 by , 22 months ago
Linux version, sorry.
But I suppose FreeBSD has the same issue.
Thanks!
comment:5 by , 22 months ago
FreeBSD and Linux ioctl()
differ, but the addressing is similar.
Is there any evidence that ATA pass-through via extender is supported by controller driver and firmware (e.g. vendor specific tool that could read SMART data) ?
comment:6 by , 22 months ago
The HighPoint CLI and GUI controller softwares see the drives as if they were connected directly to the RR4520 itself, and I can access the SMART data just fine from said softwares.
comment:7 by , 21 months ago
I asked ChatGPT about it, and this is the code snippet it replied with (for 1/E6/1 as an exemple):
#include <linux/hpt_iop.h>
int fd; File descriptor for the device
Fill in the SCSI command buffer
unsigned char inquiry_cmd[] = { 0x12, 0x00, 0x00, 0x00, 0xff, 0x00 };
Fill in the command info structure
struct hpt_cmd_info cmd_info;
memset(&cmd_info, 0, sizeof(cmd_info));
cmd_info.cdb_length = sizeof(inquiry_cmd);
cmd_info.cdb_ptr = inquiry_cmd;
cmd_info.bus = 0;
cmd_info.target = 0xe6;
cmd_info.lun = 1;
Send the command
int result = ioctl(fd, HPT_IOCTL_CMD, &cmd_info);
if (result < 0) {
Handle the error
}
It seems to be 0xe6, but I might not have asked the right question.
comment:8 by , 21 months ago
I also asked HighPoint technical support, but I'm still waiting for a reply.
comment:9 by , 21 months ago
When I asked "So would the array for deviceid be { 0x01, 0xe6, 0x01 }?"
I got the following reply:
Yes, that's correct. In the hpt_cmd_info structure, you'll need to set the bus, target, and lun fields to target the device with ID 1/E6/1. The bus field is typically set to 0 for HighPoint RAID controllers, so you can set it to 0. The target field should be set to the decimal representation of the second byte in the device ID (which is 0xE6 in hexadecimal notation), and the lun field should be set to the decimal representation of the third byte in the device ID (which is 0x01 in this case).
So you can set the bus field to 0, the target field to 230 (0xE6 in decimal), and the lun field to 1, like this:
cmd_info.bus = 0;
cmd_info.target = 230;
cmd_info.lun = 1;
And when you pass this cmd_info structure to the HPT_IOCTL_CMD ioctl command, the driver will send the SCSI command to the device with ID 1/E6/1.
comment:10 by , 21 months ago
This seems to be extracted from other sources possibly using a different API. The naming of the three parameters is not consistent with the very old hpt related code from 2006 (r2237) in os_linux.cpp
.
If you want to try with the enhanced value ranges, checkout smartmontools from SVN or load and unpack a recent *.src.tar.gz file from https://builds.smartmontools.org/, apply this patch ...
-
os_linux.cpp
3567 3567 int len = strlen(type); 3568 3568 if (!(n2 == len || n3 == len)) 3569 3569 return set_err_np(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items"); 3570 if (!( 1 <= controller && controller <= 8))3570 if (!(0 <= controller && controller <= 255)) 3571 3571 return set_err_np(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied"); 3572 if (!( 1 <= channel && channel <= 128))3572 if (!(0 <= channel && channel <= 255)) 3573 3573 return set_err_np(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied"); 3574 if (!( 1 <= disknum && disknum <= 15))3574 if (!(0 <= disknum && disknum <= 255)) 3575 3575 return set_err_np(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied"); 3576 3576 return new linux_highpoint_device(this, name, controller, channel, disknum); 3577 3577 }
... build smartctl
(make install
is not needed) and try with ./smartctl -d hpt,1/225/1 ...
(for 1/E1/1
) or so.
comment:11 by , 21 months ago
Sadly it doesn't work. It gives me the same "Read device identity failed" with 255 as it does with any other number.
Since I managed to build from source though, I can try out other changes in the source code if you have any other ideas.
Thanks for your help!
comment:12 by , 21 months ago
I provided ChatGPT with the old code you linked above (r2237) and asked it to modify it to support channel numbers with "E" in them. This is what it replied. Does it make sense to you?
To support channel numbers with "E" in them, you need to modify the highpoint_command_interface function, specifically line 1438-1445 where the hpt_buff is filled with controller, channel, and pmport number. One way to achieve this is to change the data type of channel number from int to char* and modify the code that fills in the channel number to handle both regular numbers and those with "E".
Here's an example of how you can modify the code:
int highpoint_command_interface(int device, smart_command_set command, char* channel, char *data) {
unsigned char hpt_buff[4*sizeof(int) + STRANGE_BUFFER_LENGTH];
unsigned int *hpt = (unsigned int *)hpt_buff;
unsigned char *buff = &hpt_buff[4*sizeof(int)];
int copydata = 0;
const int HDIO_DRIVE_CMD_OFFSET = 4;
memset(hpt_buff, 0, 4*sizeof(int) + STRANGE_BUFFER_LENGTH);
hpt[0] = con->hpt_data[0]; controller id
if (channel[0] == 'E') {
hpt[1] = atoi(channel + 1) + 0x100;
} else {
hpt[1] = atoi(channel);
buff[0] = ATA_SMART_CMD;
switch (command) {
case CHECK_POWER_MODE:
buff[0] = ATA_CHECK_POWER_MODE;
copydata = 1;
break;
case READ_VALUES:
buff[2] = ATA_SMART_READ_VALUES;
buff[3] = 1;
copydata = 512;
break;
...
}
...
}
In this modified code, the channel argument is a char* instead of an int. The code that fills in the channel number (line 1443) checks if the first character of the channel string is "E". If it is, it converts the number after "E" to an integer using atoi() and adds 256 to it (0x100 in hex) to set the high bit. If the first character of channel is not "E", it simply converts the entire string to an integer using atoi().
Note that this assumes that channel numbers with "E" are always prefixed with a single "E" character. If your input format differs from this, you will need to adjust the code accordingly.
comment:13 by , 21 months ago
I'm doing trials and errors (mostly errors) getting it to work. I'll update once I get it right.
comment:14 by , 21 months ago
It obviously does not make any sense to add 0x100
for Enn
parameters because you already reported that this did not work, see your comment above.
comment:15 by , 21 months ago
Yeah, I figured that out. Still trying things out by modifying the code. I'm also in talks with HighPoint support and provided them the link to this ticket, so hopefully this should be resolved relatively soon!
comment:16 by , 21 months ago
I take my last comment back. The controller/channel/port are limited to 8-bit values but the target field has 32-bit values.
Revert to original code, apply this patch ...
-
os_linux.cpp
2345 2345 { 2346 2346 public: 2347 2347 linux_highpoint_device(smart_interface * intf, const char * dev_name, 2348 unsigned c har controller, unsigned char channel, unsigned charport);2348 unsigned controller, unsigned channel, unsigned port); 2349 2349 2350 2350 protected: 2351 2351 virtual int ata_command_interface(smart_command_set command, int select, char * data); 2352 2352 2353 2353 private: 2354 unsigned charm_hpt_data[3]; ///< controller/channel/port2354 unsigned m_hpt_data[3]; ///< controller/channel/port 2355 2355 }; 2356 2356 2357 2357 linux_highpoint_device::linux_highpoint_device(smart_interface * intf, const char * dev_name, 2358 unsigned c har controller, unsigned char channel, unsigned charport)2358 unsigned controller, unsigned channel, unsigned port) 2359 2359 : smart_device(intf, dev_name, "hpt", "hpt"), 2360 2360 linux_smart_device(O_RDONLY | O_NONBLOCK) 2361 2361 { … … 3572 3572 int len = strlen(type); 3573 3573 if (!(n2 == len || n3 == len)) 3574 3574 return set_err_np(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items"); 3575 #if 0 3575 3576 if (!(1 <= controller && controller <= 8)) 3576 3577 return set_err_np(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied"); 3577 3578 if (!(1 <= channel && channel <= 128)) … … 3578 3579 return set_err_np(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied"); 3579 3580 if (!(1 <= disknum && disknum <= 15)) 3580 3581 return set_err_np(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied"); 3582 #endif 3581 3583 return new linux_highpoint_device(this, name, controller, channel, disknum); 3582 3584 }
... and try ./smartctl -d hpt,1/257/1 ...
(for 1/E1/1
).
comment:17 by , 21 months ago
Sadly, same result : Read Device Identity failed: Operation not permitted.
Same message I get with any other number as the channel number.
comment:18 by , 21 months ago
Turns out my RR4520 card isn't compatible with smartctl.
So it probably works just fine with the fix you provided for EJ340 extender if used with a compatible card.
I've been trying to use the ioctl() calls specific to the hptiop.h header file to query the RR4520 without success, so I just bit the bullet and purchased a LSI SAS 9305-24i yesterday to replace my RR4520 and EJ340 extenders.
Regardless, thanks a lot for your help!
FreeBSD or Linux? The option
-d hpt,....
is available on both platforms.The three values are passed as a numeric byte array to the vendor specific
ioctl()
, for example-d hpt,1/2/3
=>{0x01,0x02,0x03}
. It is not yet known how to handle1/E1/1
. May be{0x01,0xe1,0x01}
or not. Leaving ticket open as undecided until someone provides this information.