1// SPDX-License-Identifier: GPL-2.0 2#include <linux/kernel.h> 3#include <linux/ide.h> 4#include <linux/slab.h> 5#include <linux/export.h> 6#include <linux/seq_file.h> 7 8#include "ide-disk.h" 9 10static int smart_enable(ide_drive_t *drive) 11{ 12 struct ide_cmd cmd; 13 struct ide_taskfile *tf = &cmd.tf; 14 15 memset(&cmd, 0, sizeof(cmd)); 16 tf->feature = ATA_SMART_ENABLE; 17 tf->lbam = ATA_SMART_LBAM_PASS; 18 tf->lbah = ATA_SMART_LBAH_PASS; 19 tf->command = ATA_CMD_SMART; 20 cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; 21 cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; 22 23 return ide_no_data_taskfile(drive, &cmd); 24} 25 26static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd) 27{ 28 struct ide_cmd cmd; 29 struct ide_taskfile *tf = &cmd.tf; 30 31 memset(&cmd, 0, sizeof(cmd)); 32 tf->feature = sub_cmd; 33 tf->nsect = 0x01; 34 tf->lbam = ATA_SMART_LBAM_PASS; 35 tf->lbah = ATA_SMART_LBAH_PASS; 36 tf->command = ATA_CMD_SMART; 37 cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; 38 cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; 39 cmd.protocol = ATA_PROT_PIO; 40 41 return ide_raw_taskfile(drive, &cmd, buf, 1); 42} 43 44static int idedisk_cache_proc_show(struct seq_file *m, void *v) 45{ 46 ide_drive_t *drive = (ide_drive_t *) m->private; 47 48 if (drive->dev_flags & IDE_DFLAG_ID_READ) 49 seq_printf(m, "%i\n", drive->id[ATA_ID_BUF_SIZE] / 2); 50 else 51 seq_printf(m, "(none)\n"); 52 return 0; 53} 54 55static int idedisk_capacity_proc_show(struct seq_file *m, void *v) 56{ 57 ide_drive_t*drive = (ide_drive_t *)m->private; 58 59 seq_printf(m, "%llu\n", (long long)ide_gd_capacity(drive)); 60 return 0; 61} 62 63static int __idedisk_proc_show(struct seq_file *m, ide_drive_t *drive, u8 sub_cmd) 64{ 65 u8 *buf; 66 67 buf = kmalloc(SECTOR_SIZE, GFP_KERNEL); 68 if (!buf) 69 return -ENOMEM; 70 71 (void)smart_enable(drive); 72 73 if (get_smart_data(drive, buf, sub_cmd) == 0) { 74 __le16 *val = (__le16 *)buf; 75 int i; 76 77 for (i = 0; i < SECTOR_SIZE / 2; i++) { 78 seq_printf(m, "%04x%c", le16_to_cpu(val[i]), 79 (i % 8) == 7 ? '\n' : ' '); 80 } 81 } 82 kfree(buf); 83 return 0; 84} 85 86static int idedisk_sv_proc_show(struct seq_file *m, void *v) 87{ 88 return __idedisk_proc_show(m, m->private, ATA_SMART_READ_VALUES); 89} 90 91static int idedisk_st_proc_show(struct seq_file *m, void *v) 92{ 93 return __idedisk_proc_show(m, m->private, ATA_SMART_READ_THRESHOLDS); 94} 95 96ide_proc_entry_t ide_disk_proc[] = { 97 { "cache", S_IFREG|S_IRUGO, idedisk_cache_proc_show }, 98 { "capacity", S_IFREG|S_IRUGO, idedisk_capacity_proc_show }, 99 { "geometry", S_IFREG|S_IRUGO, ide_geometry_proc_show }, 100 { "smart_values", S_IFREG|S_IRUSR, idedisk_sv_proc_show }, 101 { "smart_thresholds", S_IFREG|S_IRUSR, idedisk_st_proc_show }, 102 {} 103}; 104 105ide_devset_rw_field(bios_cyl, bios_cyl); 106ide_devset_rw_field(bios_head, bios_head); 107ide_devset_rw_field(bios_sect, bios_sect); 108ide_devset_rw_field(failures, failures); 109ide_devset_rw_field(lun, lun); 110ide_devset_rw_field(max_failures, max_failures); 111 112const struct ide_proc_devset ide_disk_settings[] = { 113 IDE_PROC_DEVSET(acoustic, 0, 254), 114 IDE_PROC_DEVSET(address, 0, 2), 115 IDE_PROC_DEVSET(bios_cyl, 0, 65535), 116 IDE_PROC_DEVSET(bios_head, 0, 255), 117 IDE_PROC_DEVSET(bios_sect, 0, 63), 118 IDE_PROC_DEVSET(failures, 0, 65535), 119 IDE_PROC_DEVSET(lun, 0, 7), 120 IDE_PROC_DEVSET(max_failures, 0, 65535), 121 IDE_PROC_DEVSET(multcount, 0, 16), 122 IDE_PROC_DEVSET(nowerr, 0, 1), 123 IDE_PROC_DEVSET(wcache, 0, 1), 124 { NULL }, 125}; 126