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 | * |
13 | * This drive supports reporting the temperature of SATA drives. It can be |
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]; |
167 | enum req_op op; |
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; |
178 | op = REQ_OP_DRV_OUT; |
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; |
186 | op = REQ_OP_DRV_IN; |
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 | |
195 | return scsi_execute_cmd(sdev: st->sdev, cmd: scsi_cmd, opf: op, buffer: st->smartdata, |
196 | bufflen: ATA_SECT_SIZE, HZ, retries: 5, NULL); |
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_command: ATA_CMD_SMART, feature, lba_low: select, |
203 | lba_mid: ATA_SMART_LBAM_PASS, lba_high: 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, feature: ATA_SMART_READ_VALUES, select: 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: |
266 | if (!temp_is_valid(buf[SCT_STATUS_TEMP])) |
267 | return -ENODATA; |
268 | *val = temp_from_sct(buf[SCT_STATUS_TEMP]); |
269 | break; |
270 | case hwmon_temp_lowest: |
271 | if (!temp_is_valid(buf[SCT_STATUS_TEMP_LOWEST])) |
272 | return -ENODATA; |
273 | *val = temp_from_sct(buf[SCT_STATUS_TEMP_LOWEST]); |
274 | break; |
275 | case hwmon_temp_highest: |
276 | if (!temp_is_valid(buf[SCT_STATUS_TEMP_HIGHEST])) |
277 | return -ENODATA; |
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 | |
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 | |
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(id: ata_id); |
354 | have_sct = ata_id_sct_supported(id: ata_id); |
355 | have_sct_data_table = ata_id_sct_data_tables(id: ata_id); |
356 | have_smart = ata_id_smart_supported(id: ata_id) && |
357 | ata_id_smart_enabled(id: 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; |
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 | |
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) |
391 | goto skip_sct_data; |
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, attr: hwmon_temp_input, temp: &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(lock: &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 | |
529 | static const struct hwmon_channel_info * const drivetemp_info[] = { |
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 | */ |
553 | static int drivetemp_add(struct device *dev) |
554 | { |
555 | struct scsi_device *sdev = to_scsi_device(dev->parent); |
556 | struct drivetemp_data *st; |
557 | int err; |
558 | |
559 | st = kzalloc(size: 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: dev->parent, name: "drivetemp" , |
573 | drvdata: st, info: &drivetemp_chip_info, |
574 | NULL); |
575 | if (IS_ERR(ptr: st->hwdev)) { |
576 | err = PTR_ERR(ptr: st->hwdev); |
577 | goto abort; |
578 | } |
579 | |
580 | list_add(new: &st->list, head: &drivetemp_devlist); |
581 | return 0; |
582 | |
583 | abort: |
584 | kfree(objp: st); |
585 | return err; |
586 | } |
587 | |
588 | static void drivetemp_remove(struct device *dev) |
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(entry: &st->list); |
595 | hwmon_device_unregister(dev: st->hwdev); |
596 | kfree(objp: 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" ); |
623 | MODULE_ALIAS("platform:drivetemp" ); |
624 | |