Skip to content

Commit 7f64b5a

Browse files
authored
Merge pull request #213 from truenas/NAS-134723
NAS-134723 / 25.10 / hwmon: (drivetemp) Add SCSI drives support
2 parents 1720d64 + 43ff910 commit 7f64b5a

File tree

1 file changed

+85
-1
lines changed

1 file changed

+85
-1
lines changed

drivers/hwmon/drivetemp.c

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
#include <scsi/scsi_device.h>
108108
#include <scsi/scsi_driver.h>
109109
#include <scsi/scsi_proto.h>
110+
#include <linux/unaligned.h>
110111

111112
struct drivetemp_data {
112113
struct list_head list; /* list of instantiated devices */
@@ -143,6 +144,13 @@ static LIST_HEAD(drivetemp_devlist);
143144
#define SCT_READ_LOG_ADDR 0xe1
144145
#define SMART_READ_LOG 0xd5
145146
#define SMART_WRITE_LOG 0xd6
147+
#define TEMP_LOG_PAGE 0xd
148+
#define TEMP_LOG_PAGE_LEN 0x10
149+
#define TEMP_LOG_INVALID 0xFF
150+
#define TEMP_LOG_HEADER_LEN 4
151+
#define TEMP_LOG_PARAM_HEADER_LEN 4
152+
#define TEMP_LOG_LEN_OFFSET 2
153+
#define TEMP_LOG_PARAM_TEMP_OFFSET 5
146154

147155
#define INVALID_TEMP 0x80
148156

@@ -324,6 +332,79 @@ static bool drivetemp_sct_avoid(struct drivetemp_data *st)
324332
return false;
325333
}
326334

335+
static int drivetemp_retrieve_temp_log(struct drivetemp_data *st,
336+
u8 *temp, u8 *reftemp)
337+
{
338+
int err;
339+
u8 scsi_cmd[MAX_COMMAND_SIZE];
340+
char buf[TEMP_LOG_PAGE_LEN];
341+
int i = TEMP_LOG_HEADER_LEN;
342+
u16 page_len;
343+
344+
memset(scsi_cmd, 0, sizeof(scsi_cmd));
345+
scsi_cmd[0] = LOG_SENSE;
346+
scsi_cmd[2] = 0x40 | TEMP_LOG_PAGE; /* Page control (PC)==1 */
347+
put_unaligned_be16(TEMP_LOG_PAGE_LEN, &scsi_cmd[7]);
348+
err = scsi_execute_cmd(st->sdev, scsi_cmd, REQ_OP_DRV_IN, buf,
349+
TEMP_LOG_PAGE_LEN, 10 * HZ, 5, NULL);
350+
if (err)
351+
return (err);
352+
353+
page_len = min(get_unaligned_be16(&buf[TEMP_LOG_LEN_OFFSET]),
354+
TEMP_LOG_PAGE_LEN - TEMP_LOG_HEADER_LEN) + TEMP_LOG_HEADER_LEN;
355+
356+
while (i + TEMP_LOG_PARAM_HEADER_LEN <= page_len) {
357+
u8 param_len = (u8) buf[i + 3] + TEMP_LOG_PARAM_HEADER_LEN;
358+
u16 param_code = get_unaligned_be16(&buf[i]);
359+
if (i + param_len > page_len)
360+
break;
361+
if (param_code == 0x0)
362+
*temp = (u8) buf[i + TEMP_LOG_PARAM_TEMP_OFFSET];
363+
if (reftemp && param_code == 0x1)
364+
*reftemp = (u8) buf[i + TEMP_LOG_PARAM_TEMP_OFFSET];
365+
i += param_len;
366+
}
367+
368+
return (0);
369+
}
370+
371+
static int drivetemp_get_scsitemp(struct drivetemp_data *st, u32 attr,
372+
long *temp)
373+
{
374+
int err;
375+
u8 temp8 = TEMP_LOG_INVALID;
376+
377+
if ((err = drivetemp_retrieve_temp_log(st, &temp8, NULL)) == 0) {
378+
if (temp8 != TEMP_LOG_INVALID)
379+
*temp = (u8) temp8 * 1000;
380+
else
381+
err = -EIO;
382+
}
383+
384+
return (err);
385+
}
386+
387+
static int drivetemp_identify_scsi(struct drivetemp_data *st)
388+
{
389+
int err;
390+
u8 temp = TEMP_LOG_INVALID, reftemp = TEMP_LOG_INVALID;
391+
392+
if ((err = drivetemp_retrieve_temp_log(st, &temp,
393+
&reftemp)) == 0) {
394+
if (temp != TEMP_LOG_INVALID) {
395+
st->get_temp = drivetemp_get_scsitemp;
396+
if (reftemp != TEMP_LOG_INVALID) {
397+
st->have_temp_crit = true;
398+
st->temp_crit = reftemp * 1000;
399+
}
400+
} else {
401+
err = -EIO;
402+
}
403+
}
404+
405+
return (err);
406+
}
407+
327408
static int drivetemp_identify_sata(struct drivetemp_data *st)
328409
{
329410
struct scsi_device *sdev = st->sdev;
@@ -437,6 +518,7 @@ static int drivetemp_identify_sata(struct drivetemp_data *st)
437518
static int drivetemp_identify(struct drivetemp_data *st)
438519
{
439520
struct scsi_device *sdev = st->sdev;
521+
int ret;
440522

441523
/* Bail out immediately if there is no inquiry data */
442524
if (!sdev->inquiry || sdev->inquiry_len < 16)
@@ -446,7 +528,9 @@ static int drivetemp_identify(struct drivetemp_data *st)
446528
if (sdev->type != TYPE_DISK && sdev->type != TYPE_ZBC)
447529
return -ENODEV;
448530

449-
return drivetemp_identify_sata(st);
531+
if ((ret = drivetemp_identify_sata(st)))
532+
ret = drivetemp_identify_scsi(st);
533+
return (ret);
450534
}
451535

452536
static int drivetemp_read(struct device *dev, enum hwmon_sensor_types type,

0 commit comments

Comments
 (0)