Commit | Line | Data |
---|---|---|
5b46903d GR |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Hwmon client for disk and solid state drives with temperature sensors | |
4 | * Copyright (C) 2019 Zodiac Inflight Innovations | |
5 | * | |
6 | * With input from: | |
7 | * Hwmon client for S.M.A.R.T. hard disk drives with temperature sensors. | |
8 | * (C) 2018 Linus Walleij | |
9 | * | |
10 | * hwmon: Driver for SCSI/ATA temperature sensors | |
11 | * by Constantin Baranov <const@mimas.ru>, submitted September 2009 | |
12 | * | |
bde58ca8 | 13 | * This drive supports reporting the temperature of SATA drives. It can be |
5b46903d GR |
14 | * easily extended to report the temperature of SCSI drives. |
15 | * | |
16 | * The primary means to read drive temperatures and temperature limits | |
17 | * for ATA drives is the SCT Command Transport feature set as specified in | |
18 | * ATA8-ACS. | |
19 | * It can be used to read the current drive temperature, temperature limits, | |
20 | * and historic minimum and maximum temperatures. The SCT Command Transport | |
21 | * feature set is documented in "AT Attachment 8 - ATA/ATAPI Command Set | |
22 | * (ATA8-ACS)". | |
23 | * | |
24 | * If the SCT Command Transport feature set is not available, drive temperatures | |
25 | * may be readable through SMART attributes. Since SMART attributes are not well | |
26 | * defined, this method is only used as fallback mechanism. | |
27 | * | |
28 | * There are three SMART attributes which may report drive temperatures. | |
29 | * Those are defined as follows (from | |
30 | * http://www.cropel.com/library/smart-attribute-list.aspx). | |
31 | * | |
32 | * 190 Temperature Temperature, monitored by a sensor somewhere inside | |
33 | * the drive. Raw value typicaly holds the actual | |
34 | * temperature (hexadecimal) in its rightmost two digits. | |
35 | * | |
36 | * 194 Temperature Temperature, monitored by a sensor somewhere inside | |
37 | * the drive. Raw value typicaly holds the actual | |
38 | * temperature (hexadecimal) in its rightmost two digits. | |
39 | * | |
40 | * 231 Temperature Temperature, monitored by a sensor somewhere inside | |
41 | * the drive. Raw value typicaly holds the actual | |
42 | * temperature (hexadecimal) in its rightmost two digits. | |
43 | * | |
44 | * Wikipedia defines attributes a bit differently. | |
45 | * | |
46 | * 190 Temperature Value is equal to (100-temp. °C), allowing manufacturer | |
47 | * Difference or to set a minimum threshold which corresponds to a | |
48 | * Airflow maximum temperature. This also follows the convention of | |
49 | * Temperature 100 being a best-case value and lower values being | |
50 | * undesirable. However, some older drives may instead | |
51 | * report raw Temperature (identical to 0xC2) or | |
52 | * Temperature minus 50 here. | |
53 | * 194 Temperature or Indicates the device temperature, if the appropriate | |
54 | * Temperature sensor is fitted. Lowest byte of the raw value contains | |
55 | * Celsius the exact temperature value (Celsius degrees). | |
56 | * 231 Life Left Indicates the approximate SSD life left, in terms of | |
57 | * (SSDs) or program/erase cycles or available reserved blocks. | |
58 | * Temperature A normalized value of 100 represents a new drive, with | |
59 | * a threshold value at 10 indicating a need for | |
60 | * replacement. A value of 0 may mean that the drive is | |
61 | * operating in read-only mode to allow data recovery. | |
62 | * Previously (pre-2010) occasionally used for Drive | |
63 | * Temperature (more typically reported at 0xC2). | |
64 | * | |
65 | * Common denominator is that the first raw byte reports the temperature | |
66 | * in degrees C on almost all drives. Some drives may report a fractional | |
67 | * temperature in the second raw byte. | |
68 | * | |
69 | * Known exceptions (from libatasmart): | |
70 | * - SAMSUNG SV0412H and SAMSUNG SV1204H) report the temperature in 10th | |
71 | * degrees C in the first two raw bytes. | |
72 | * - A few Maxtor drives report an unknown or bad value in attribute 194. | |
73 | * - Certain Apple SSD drives report an unknown value in attribute 190. | |
74 | * Only certain firmware versions are affected. | |
75 | * | |
76 | * Those exceptions affect older ATA drives and are currently ignored. | |
77 | * Also, the second raw byte (possibly reporting the fractional temperature) | |
78 | * is currently ignored. | |
79 | * | |
80 | * Many drives also report temperature limits in additional SMART data raw | |
81 | * bytes. The format of those is not well defined and varies widely. | |
82 | * The driver does not currently attempt to report those limits. | |
83 | * | |
84 | * According to data in smartmontools, attribute 231 is rarely used to report | |
85 | * drive temperatures. At the same time, several drives report SSD life left | |
86 | * in attribute 231, but do not support temperature sensors. For this reason, | |
87 | * attribute 231 is currently ignored. | |
88 | * | |
89 | * Following above definitions, temperatures are reported as follows. | |
90 | * If SCT Command Transport is supported, it is used to read the | |
91 | * temperature and, if available, temperature limits. | |
92 | * - Otherwise, if SMART attribute 194 is supported, it is used to read | |
93 | * the temperature. | |
94 | * - Otherwise, if SMART attribute 190 is supported, it is used to read | |
95 | * the temperature. | |
96 | */ | |
97 | ||
98 | #include <linux/ata.h> | |
99 | #include <linux/bits.h> | |
100 | #include <linux/device.h> | |
101 | #include <linux/hwmon.h> | |
102 | #include <linux/kernel.h> | |
103 | #include <linux/list.h> | |
104 | #include <linux/module.h> | |
105 | #include <linux/mutex.h> | |
106 | #include <scsi/scsi_cmnd.h> | |
107 | #include <scsi/scsi_device.h> | |
108 | #include <scsi/scsi_driver.h> | |
109 | #include <scsi/scsi_proto.h> | |
110 | ||
111 | struct drivetemp_data { | |
112 | struct list_head list; /* list of instantiated devices */ | |
113 | struct mutex lock; /* protect data buffer accesses */ | |
114 | struct scsi_device *sdev; /* SCSI device */ | |
115 | struct device *dev; /* instantiating device */ | |
116 | struct device *hwdev; /* hardware monitoring device */ | |
117 | u8 smartdata[ATA_SECT_SIZE]; /* local buffer */ | |
118 | int (*get_temp)(struct drivetemp_data *st, u32 attr, long *val); | |
119 | bool have_temp_lowest; /* lowest temp in SCT status */ | |
120 | bool have_temp_highest; /* highest temp in SCT status */ | |
121 | bool have_temp_min; /* have min temp */ | |
122 | bool have_temp_max; /* have max temp */ | |
123 | bool have_temp_lcrit; /* have lower critical limit */ | |
124 | bool have_temp_crit; /* have critical limit */ | |
125 | int temp_min; /* min temp */ | |
126 | int temp_max; /* max temp */ | |
127 | int temp_lcrit; /* lower critical limit */ | |
128 | int temp_crit; /* critical limit */ | |
129 | }; | |
130 | ||
131 | static LIST_HEAD(drivetemp_devlist); | |
132 | ||
133 | #define ATA_MAX_SMART_ATTRS 30 | |
134 | #define SMART_TEMP_PROP_190 190 | |
135 | #define SMART_TEMP_PROP_194 194 | |
136 | ||
137 | #define SCT_STATUS_REQ_ADDR 0xe0 | |
138 | #define SCT_STATUS_VERSION_LOW 0 /* log byte offsets */ | |
139 | #define SCT_STATUS_VERSION_HIGH 1 | |
140 | #define SCT_STATUS_TEMP 200 | |
141 | #define SCT_STATUS_TEMP_LOWEST 201 | |
142 | #define SCT_STATUS_TEMP_HIGHEST 202 | |
143 | #define SCT_READ_LOG_ADDR 0xe1 | |
144 | #define SMART_READ_LOG 0xd5 | |
145 | #define SMART_WRITE_LOG 0xd6 | |
146 | ||
147 | #define INVALID_TEMP 0x80 | |
148 | ||
149 | #define temp_is_valid(temp) ((temp) != INVALID_TEMP) | |
150 | #define temp_from_sct(temp) (((s8)(temp)) * 1000) | |
151 | ||
152 | static inline bool ata_id_smart_supported(u16 *id) | |
153 | { | |
154 | return id[ATA_ID_COMMAND_SET_1] & BIT(0); | |
155 | } | |
156 | ||
157 | static inline bool ata_id_smart_enabled(u16 *id) | |
158 | { | |
159 | return id[ATA_ID_CFS_ENABLE_1] & BIT(0); | |
160 | } | |
161 | ||
162 | static int drivetemp_scsi_command(struct drivetemp_data *st, | |
163 | u8 ata_command, u8 feature, | |
164 | u8 lba_low, u8 lba_mid, u8 lba_high) | |
165 | { | |
166 | u8 scsi_cmd[MAX_COMMAND_SIZE]; | |
08e95a2b | 167 | enum req_op op; |
5b46903d GR |
168 | |
169 | memset(scsi_cmd, 0, sizeof(scsi_cmd)); | |
170 | scsi_cmd[0] = ATA_16; | |
171 | if (ata_command == ATA_CMD_SMART && feature == SMART_WRITE_LOG) { | |
172 | scsi_cmd[1] = (5 << 1); /* PIO Data-out */ | |
173 | /* | |
174 | * No off.line or cc, write to dev, block count in sector count | |
175 | * field. | |
176 | */ | |
177 | scsi_cmd[2] = 0x06; | |
08e95a2b | 178 | op = REQ_OP_DRV_OUT; |
5b46903d GR |
179 | } else { |
180 | scsi_cmd[1] = (4 << 1); /* PIO Data-in */ | |
181 | /* | |
182 | * No off.line or cc, read from dev, block count in sector count | |
183 | * field. | |
184 | */ | |
185 | scsi_cmd[2] = 0x0e; | |
08e95a2b | 186 | op = REQ_OP_DRV_IN; |
5b46903d GR |
187 | } |
188 | scsi_cmd[4] = feature; | |
189 | scsi_cmd[6] = 1; /* 1 sector */ | |
190 | scsi_cmd[8] = lba_low; | |
191 | scsi_cmd[10] = lba_mid; | |
192 | scsi_cmd[12] = lba_high; | |
193 | scsi_cmd[14] = ata_command; | |
194 | ||
08e95a2b MC |
195 | return scsi_execute_cmd(st->sdev, scsi_cmd, op, st->smartdata, |
196 | ATA_SECT_SIZE, HZ, 5, NULL); | |
5b46903d GR |
197 | } |
198 | ||
199 | static int drivetemp_ata_command(struct drivetemp_data *st, u8 feature, | |
200 | u8 select) | |
201 | { | |
202 | return drivetemp_scsi_command(st, ATA_CMD_SMART, feature, select, | |
203 | ATA_SMART_LBAM_PASS, ATA_SMART_LBAH_PASS); | |
204 | } | |
205 | ||
206 | static int drivetemp_get_smarttemp(struct drivetemp_data *st, u32 attr, | |
207 | long *temp) | |
208 | { | |
209 | u8 *buf = st->smartdata; | |
210 | bool have_temp = false; | |
211 | u8 temp_raw; | |
212 | u8 csum; | |
213 | int err; | |
214 | int i; | |
215 | ||
216 | err = drivetemp_ata_command(st, ATA_SMART_READ_VALUES, 0); | |
217 | if (err) | |
218 | return err; | |
219 | ||
220 | /* Checksum the read value table */ | |
221 | csum = 0; | |
222 | for (i = 0; i < ATA_SECT_SIZE; i++) | |
223 | csum += buf[i]; | |
224 | if (csum) { | |
225 | dev_dbg(&st->sdev->sdev_gendev, | |
226 | "checksum error reading SMART values\n"); | |
227 | return -EIO; | |
228 | } | |
229 | ||
230 | for (i = 0; i < ATA_MAX_SMART_ATTRS; i++) { | |
231 | u8 *attr = buf + i * 12; | |
232 | int id = attr[2]; | |
233 | ||
234 | if (!id) | |
235 | continue; | |
236 | ||
237 | if (id == SMART_TEMP_PROP_190) { | |
238 | temp_raw = attr[7]; | |
239 | have_temp = true; | |
240 | } | |
241 | if (id == SMART_TEMP_PROP_194) { | |
242 | temp_raw = attr[7]; | |
243 | have_temp = true; | |
244 | break; | |
245 | } | |
246 | } | |
247 | ||
248 | if (have_temp) { | |
249 | *temp = temp_raw * 1000; | |
250 | return 0; | |
251 | } | |
252 | ||
253 | return -ENXIO; | |
254 | } | |
255 | ||
256 | static int drivetemp_get_scttemp(struct drivetemp_data *st, u32 attr, long *val) | |
257 | { | |
258 | u8 *buf = st->smartdata; | |
259 | int err; | |
260 | ||
261 | err = drivetemp_ata_command(st, SMART_READ_LOG, SCT_STATUS_REQ_ADDR); | |
262 | if (err) | |
263 | return err; | |
264 | switch (attr) { | |
265 | case hwmon_temp_input: | |
ed08ebb7 GR |
266 | if (!temp_is_valid(buf[SCT_STATUS_TEMP])) |
267 | return -ENODATA; | |
5b46903d GR |
268 | *val = temp_from_sct(buf[SCT_STATUS_TEMP]); |
269 | break; | |
270 | case hwmon_temp_lowest: | |
ed08ebb7 GR |
271 | if (!temp_is_valid(buf[SCT_STATUS_TEMP_LOWEST])) |
272 | return -ENODATA; | |
5b46903d GR |
273 | *val = temp_from_sct(buf[SCT_STATUS_TEMP_LOWEST]); |
274 | break; | |
275 | case hwmon_temp_highest: | |
ed08ebb7 GR |
276 | if (!temp_is_valid(buf[SCT_STATUS_TEMP_HIGHEST])) |
277 | return -ENODATA; | |
5b46903d GR |
278 | *val = temp_from_sct(buf[SCT_STATUS_TEMP_HIGHEST]); |
279 | break; | |
280 | default: | |
281 | err = -EINVAL; | |
282 | break; | |
283 | } | |
284 | return err; | |
285 | } | |
286 | ||
c66ef39e MS |
287 | static const char * const sct_avoid_models[] = { |
288 | /* | |
289 | * These drives will have WRITE FPDMA QUEUED command timeouts and sometimes just | |
290 | * freeze until power-cycled under heavy write loads when their temperature is | |
291 | * getting polled in SCT mode. The SMART mode seems to be fine, though. | |
292 | * | |
293 | * While only the 3 TB model (DT01ACA3) was actually caught exhibiting the | |
294 | * problem let's play safe here to avoid data corruption and ban the whole | |
295 | * DT01ACAx family. | |
296 | ||
297 | * The models from this array are prefix-matched. | |
298 | */ | |
299 | "TOSHIBA DT01ACA", | |
300 | }; | |
301 | ||
302 | static bool drivetemp_sct_avoid(struct drivetemp_data *st) | |
303 | { | |
304 | struct scsi_device *sdev = st->sdev; | |
305 | unsigned int ctr; | |
306 | ||
307 | if (!sdev->model) | |
308 | return false; | |
309 | ||
310 | /* | |
311 | * The "model" field contains just the raw SCSI INQUIRY response | |
312 | * "product identification" field, which has a width of 16 bytes. | |
313 | * This field is space-filled, but is NOT NULL-terminated. | |
314 | */ | |
315 | for (ctr = 0; ctr < ARRAY_SIZE(sct_avoid_models); ctr++) | |
316 | if (!strncmp(sdev->model, sct_avoid_models[ctr], | |
317 | strlen(sct_avoid_models[ctr]))) | |
318 | return true; | |
319 | ||
320 | return false; | |
321 | } | |
322 | ||
5b46903d GR |
323 | static int drivetemp_identify_sata(struct drivetemp_data *st) |
324 | { | |
325 | struct scsi_device *sdev = st->sdev; | |
326 | u8 *buf = st->smartdata; | |
327 | struct scsi_vpd *vpd; | |
328 | bool is_ata, is_sata; | |
329 | bool have_sct_data_table; | |
330 | bool have_sct_temp; | |
331 | bool have_smart; | |
332 | bool have_sct; | |
333 | u16 *ata_id; | |
334 | u16 version; | |
335 | long temp; | |
336 | int err; | |
337 | ||
338 | /* SCSI-ATA Translation present? */ | |
339 | rcu_read_lock(); | |
340 | vpd = rcu_dereference(sdev->vpd_pg89); | |
341 | ||
342 | /* | |
343 | * Verify that ATA IDENTIFY DEVICE data is included in ATA Information | |
344 | * VPD and that the drive implements the SATA protocol. | |
345 | */ | |
346 | if (!vpd || vpd->len < 572 || vpd->data[56] != ATA_CMD_ID_ATA || | |
347 | vpd->data[36] != 0x34) { | |
348 | rcu_read_unlock(); | |
349 | return -ENODEV; | |
350 | } | |
351 | ata_id = (u16 *)&vpd->data[60]; | |
352 | is_ata = ata_id_is_ata(ata_id); | |
353 | is_sata = ata_id_is_sata(ata_id); | |
354 | have_sct = ata_id_sct_supported(ata_id); | |
355 | have_sct_data_table = ata_id_sct_data_tables(ata_id); | |
356 | have_smart = ata_id_smart_supported(ata_id) && | |
357 | ata_id_smart_enabled(ata_id); | |
358 | ||
359 | rcu_read_unlock(); | |
360 | ||
361 | /* bail out if this is not a SATA device */ | |
362 | if (!is_ata || !is_sata) | |
363 | return -ENODEV; | |
c66ef39e MS |
364 | |
365 | if (have_sct && drivetemp_sct_avoid(st)) { | |
366 | dev_notice(&sdev->sdev_gendev, | |
367 | "will avoid using SCT for temperature monitoring\n"); | |
368 | have_sct = false; | |
369 | } | |
370 | ||
5b46903d GR |
371 | if (!have_sct) |
372 | goto skip_sct; | |
373 | ||
374 | err = drivetemp_ata_command(st, SMART_READ_LOG, SCT_STATUS_REQ_ADDR); | |
375 | if (err) | |
376 | goto skip_sct; | |
377 | ||
378 | version = (buf[SCT_STATUS_VERSION_HIGH] << 8) | | |
379 | buf[SCT_STATUS_VERSION_LOW]; | |
380 | if (version != 2 && version != 3) | |
381 | goto skip_sct; | |
382 | ||
383 | have_sct_temp = temp_is_valid(buf[SCT_STATUS_TEMP]); | |
384 | if (!have_sct_temp) | |
385 | goto skip_sct; | |
386 | ||
387 | st->have_temp_lowest = temp_is_valid(buf[SCT_STATUS_TEMP_LOWEST]); | |
388 | st->have_temp_highest = temp_is_valid(buf[SCT_STATUS_TEMP_HIGHEST]); | |
389 | ||
390 | if (!have_sct_data_table) | |
bcb543cc | 391 | goto skip_sct_data; |
5b46903d GR |
392 | |
393 | /* Request and read temperature history table */ | |
394 | memset(buf, '\0', sizeof(st->smartdata)); | |
395 | buf[0] = 5; /* data table command */ | |
396 | buf[2] = 1; /* read table */ | |
397 | buf[4] = 2; /* temperature history table */ | |
398 | ||
399 | err = drivetemp_ata_command(st, SMART_WRITE_LOG, SCT_STATUS_REQ_ADDR); | |
400 | if (err) | |
401 | goto skip_sct_data; | |
402 | ||
403 | err = drivetemp_ata_command(st, SMART_READ_LOG, SCT_READ_LOG_ADDR); | |
404 | if (err) | |
405 | goto skip_sct_data; | |
406 | ||
407 | /* | |
408 | * Temperature limits per AT Attachment 8 - | |
409 | * ATA/ATAPI Command Set (ATA8-ACS) | |
410 | */ | |
411 | st->have_temp_max = temp_is_valid(buf[6]); | |
412 | st->have_temp_crit = temp_is_valid(buf[7]); | |
413 | st->have_temp_min = temp_is_valid(buf[8]); | |
414 | st->have_temp_lcrit = temp_is_valid(buf[9]); | |
415 | ||
416 | st->temp_max = temp_from_sct(buf[6]); | |
417 | st->temp_crit = temp_from_sct(buf[7]); | |
418 | st->temp_min = temp_from_sct(buf[8]); | |
419 | st->temp_lcrit = temp_from_sct(buf[9]); | |
420 | ||
421 | skip_sct_data: | |
422 | if (have_sct_temp) { | |
423 | st->get_temp = drivetemp_get_scttemp; | |
424 | return 0; | |
425 | } | |
426 | skip_sct: | |
427 | if (!have_smart) | |
428 | return -ENODEV; | |
429 | st->get_temp = drivetemp_get_smarttemp; | |
430 | return drivetemp_get_smarttemp(st, hwmon_temp_input, &temp); | |
431 | } | |
432 | ||
433 | static int drivetemp_identify(struct drivetemp_data *st) | |
434 | { | |
435 | struct scsi_device *sdev = st->sdev; | |
436 | ||
437 | /* Bail out immediately if there is no inquiry data */ | |
438 | if (!sdev->inquiry || sdev->inquiry_len < 16) | |
439 | return -ENODEV; | |
440 | ||
441 | /* Disk device? */ | |
442 | if (sdev->type != TYPE_DISK && sdev->type != TYPE_ZBC) | |
443 | return -ENODEV; | |
444 | ||
445 | return drivetemp_identify_sata(st); | |
446 | } | |
447 | ||
448 | static int drivetemp_read(struct device *dev, enum hwmon_sensor_types type, | |
449 | u32 attr, int channel, long *val) | |
450 | { | |
451 | struct drivetemp_data *st = dev_get_drvdata(dev); | |
452 | int err = 0; | |
453 | ||
454 | if (type != hwmon_temp) | |
455 | return -EINVAL; | |
456 | ||
457 | switch (attr) { | |
458 | case hwmon_temp_input: | |
459 | case hwmon_temp_lowest: | |
460 | case hwmon_temp_highest: | |
461 | mutex_lock(&st->lock); | |
462 | err = st->get_temp(st, attr, val); | |
463 | mutex_unlock(&st->lock); | |
464 | break; | |
465 | case hwmon_temp_lcrit: | |
466 | *val = st->temp_lcrit; | |
467 | break; | |
468 | case hwmon_temp_min: | |
469 | *val = st->temp_min; | |
470 | break; | |
471 | case hwmon_temp_max: | |
472 | *val = st->temp_max; | |
473 | break; | |
474 | case hwmon_temp_crit: | |
475 | *val = st->temp_crit; | |
476 | break; | |
477 | default: | |
478 | err = -EINVAL; | |
479 | break; | |
480 | } | |
481 | return err; | |
482 | } | |
483 | ||
484 | static umode_t drivetemp_is_visible(const void *data, | |
485 | enum hwmon_sensor_types type, | |
486 | u32 attr, int channel) | |
487 | { | |
488 | const struct drivetemp_data *st = data; | |
489 | ||
490 | switch (type) { | |
491 | case hwmon_temp: | |
492 | switch (attr) { | |
493 | case hwmon_temp_input: | |
494 | return 0444; | |
495 | case hwmon_temp_lowest: | |
496 | if (st->have_temp_lowest) | |
497 | return 0444; | |
498 | break; | |
499 | case hwmon_temp_highest: | |
500 | if (st->have_temp_highest) | |
501 | return 0444; | |
502 | break; | |
503 | case hwmon_temp_min: | |
504 | if (st->have_temp_min) | |
505 | return 0444; | |
506 | break; | |
507 | case hwmon_temp_max: | |
508 | if (st->have_temp_max) | |
509 | return 0444; | |
510 | break; | |
511 | case hwmon_temp_lcrit: | |
512 | if (st->have_temp_lcrit) | |
513 | return 0444; | |
514 | break; | |
515 | case hwmon_temp_crit: | |
516 | if (st->have_temp_crit) | |
517 | return 0444; | |
518 | break; | |
519 | default: | |
520 | break; | |
521 | } | |
522 | break; | |
523 | default: | |
524 | break; | |
525 | } | |
526 | return 0; | |
527 | } | |
528 | ||
b9adb6b6 | 529 | static const struct hwmon_channel_info * const drivetemp_info[] = { |
5b46903d GR |
530 | HWMON_CHANNEL_INFO(chip, |
531 | HWMON_C_REGISTER_TZ), | |
532 | HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | | |
533 | HWMON_T_LOWEST | HWMON_T_HIGHEST | | |
534 | HWMON_T_MIN | HWMON_T_MAX | | |
535 | HWMON_T_LCRIT | HWMON_T_CRIT), | |
536 | NULL | |
537 | }; | |
538 | ||
539 | static const struct hwmon_ops drivetemp_ops = { | |
540 | .is_visible = drivetemp_is_visible, | |
541 | .read = drivetemp_read, | |
542 | }; | |
543 | ||
544 | static const struct hwmon_chip_info drivetemp_chip_info = { | |
545 | .ops = &drivetemp_ops, | |
546 | .info = drivetemp_info, | |
547 | }; | |
548 | ||
549 | /* | |
550 | * The device argument points to sdev->sdev_dev. Its parent is | |
551 | * sdev->sdev_gendev, which we can use to get the scsi_device pointer. | |
552 | */ | |
2243acd5 | 553 | static int drivetemp_add(struct device *dev) |
5b46903d GR |
554 | { |
555 | struct scsi_device *sdev = to_scsi_device(dev->parent); | |
556 | struct drivetemp_data *st; | |
557 | int err; | |
558 | ||
559 | st = kzalloc(sizeof(*st), GFP_KERNEL); | |
560 | if (!st) | |
561 | return -ENOMEM; | |
562 | ||
563 | st->sdev = sdev; | |
564 | st->dev = dev; | |
565 | mutex_init(&st->lock); | |
566 | ||
567 | if (drivetemp_identify(st)) { | |
568 | err = -ENODEV; | |
569 | goto abort; | |
570 | } | |
571 | ||
572 | st->hwdev = hwmon_device_register_with_info(dev->parent, "drivetemp", | |
573 | st, &drivetemp_chip_info, | |
574 | NULL); | |
575 | if (IS_ERR(st->hwdev)) { | |
576 | err = PTR_ERR(st->hwdev); | |
577 | goto abort; | |
578 | } | |
579 | ||
580 | list_add(&st->list, &drivetemp_devlist); | |
581 | return 0; | |
582 | ||
583 | abort: | |
584 | kfree(st); | |
585 | return err; | |
586 | } | |
587 | ||
2243acd5 | 588 | static void drivetemp_remove(struct device *dev) |
5b46903d GR |
589 | { |
590 | struct drivetemp_data *st, *tmp; | |
591 | ||
592 | list_for_each_entry_safe(st, tmp, &drivetemp_devlist, list) { | |
593 | if (st->dev == dev) { | |
594 | list_del(&st->list); | |
595 | hwmon_device_unregister(st->hwdev); | |
596 | kfree(st); | |
597 | break; | |
598 | } | |
599 | } | |
600 | } | |
601 | ||
602 | static struct class_interface drivetemp_interface = { | |
603 | .add_dev = drivetemp_add, | |
604 | .remove_dev = drivetemp_remove, | |
605 | }; | |
606 | ||
607 | static int __init drivetemp_init(void) | |
608 | { | |
609 | return scsi_register_interface(&drivetemp_interface); | |
610 | } | |
611 | ||
612 | static void __exit drivetemp_exit(void) | |
613 | { | |
614 | scsi_unregister_interface(&drivetemp_interface); | |
615 | } | |
616 | ||
617 | module_init(drivetemp_init); | |
618 | module_exit(drivetemp_exit); | |
619 | ||
620 | MODULE_AUTHOR("Guenter Roeck <linus@roeck-us.net>"); | |
621 | MODULE_DESCRIPTION("Hard drive temperature monitor"); | |
622 | MODULE_LICENSE("GPL"); | |
5918036c | 623 | MODULE_ALIAS("platform:drivetemp"); |