Opened 14 months ago

Last modified 13 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 PsychOsmosis, 14 months ago

Component: allsmartctl

comment:2 by Christian Franke, 14 months ago

Component: smartctlall
Keywords: highpoint added
Milestone: undecided
Type: defectenhancement

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 handle 1/E1/1. May be {0x01,0xe1,0x01} or not. Leaving ticket open as undecided until someone provides this information.

comment:3 by Christian Franke, 14 months ago

Keywords: linux freebsd added
Summary: HighPoint smartctl invalid formatSupport for HighPoint controller with EJ340 extender

comment:4 by PsychOsmosis, 14 months ago

Linux version, sorry.
But I suppose FreeBSD has the same issue.

Thanks!

comment:5 by Christian Franke, 14 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 PsychOsmosis, 14 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 PsychOsmosis, 14 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 PsychOsmosis, 14 months ago

I also asked HighPoint technical support, but I'm still waiting for a reply.

comment:9 by PsychOsmosis, 14 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 Christian Franke, 14 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

     
    35673567    int len = strlen(type);
    35683568    if (!(n2 == len || n3 == len))
    35693569      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))
    35713571      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))
    35733573      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))
    35753575      return set_err_np(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied");
    35763576    return new linux_highpoint_device(this, name, controller, channel, disknum);
    35773577  }

... 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 PsychOsmosis, 13 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 PsychOsmosis, 13 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);

}
hpt[3] = con->hpt_data[2]; pmport number

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 PsychOsmosis, 13 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 Christian Franke, 13 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 PsychOsmosis, 13 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 Christian Franke, 13 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

     
    23452345{
    23462346public:
    23472347  linux_highpoint_device(smart_interface * intf, const char * dev_name,
    2348     unsigned char controller, unsigned char channel, unsigned char port);
     2348    unsigned controller, unsigned channel, unsigned port);
    23492349
    23502350protected:
    23512351  virtual int ata_command_interface(smart_command_set command, int select, char * data);
    23522352
    23532353private:
    2354   unsigned char m_hpt_data[3]; ///< controller/channel/port
     2354  unsigned m_hpt_data[3]; ///< controller/channel/port
    23552355};
    23562356
    23572357linux_highpoint_device::linux_highpoint_device(smart_interface * intf, const char * dev_name,
    2358   unsigned char controller, unsigned char channel, unsigned char port)
     2358  unsigned controller, unsigned channel, unsigned port)
    23592359: smart_device(intf, dev_name, "hpt", "hpt"),
    23602360  linux_smart_device(O_RDONLY | O_NONBLOCK)
    23612361{
     
    35723572    int len = strlen(type);
    35733573    if (!(n2 == len || n3 == len))
    35743574      return set_err_np(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items");
     3575#if 0
    35753576    if (!(1 <= controller && controller <= 8))
    35763577      return set_err_np(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied");
    35773578    if (!(1 <= channel && channel <= 128))
     
    35783579      return set_err_np(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied");
    35793580    if (!(1 <= disknum && disknum <= 15))
    35803581      return set_err_np(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied");
     3582#endif
    35813583    return new linux_highpoint_device(this, name, controller, channel, disknum);
    35823584  }

... and try ./smartctl -d hpt,1/257/1 ... (for 1/E1/1).

comment:17 by PsychOsmosis, 13 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 PsychOsmosis, 13 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!

Note: See TracTickets for help on using tickets.