107107#include <scsi/scsi_device.h>
108108#include <scsi/scsi_driver.h>
109109#include <scsi/scsi_proto.h>
110+ #include <linux/unaligned.h>
110111
111112struct 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+
327408static 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)
437518static 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
452536static int drivetemp_read (struct device * dev , enum hwmon_sensor_types type ,
0 commit comments