linux/drivers/ide/ide-proc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  Copyright (C) 1997-1998     Mark Lord
   4 *  Copyright (C) 2003          Red Hat
   5 *
   6 *  Some code was moved here from ide.c, see it for original copyrights.
   7 */
   8
   9/*
  10 * This is the /proc/ide/ filesystem implementation.
  11 *
  12 * Drive/Driver settings can be retrieved by reading the drive's
  13 * "settings" files.  e.g.    "cat /proc/ide0/hda/settings"
  14 * To write a new value "val" into a specific setting "name", use:
  15 *   echo "name:val" >/proc/ide/ide0/hda/settings
  16 */
  17
  18#include <linux/module.h>
  19
  20#include <linux/uaccess.h>
  21#include <linux/errno.h>
  22#include <linux/proc_fs.h>
  23#include <linux/stat.h>
  24#include <linux/mm.h>
  25#include <linux/pci.h>
  26#include <linux/ctype.h>
  27#include <linux/ide.h>
  28#include <linux/seq_file.h>
  29#include <linux/slab.h>
  30
  31#include <asm/io.h>
  32
  33static struct proc_dir_entry *proc_ide_root;
  34
  35static int ide_imodel_proc_show(struct seq_file *m, void *v)
  36{
  37        ide_hwif_t      *hwif = (ide_hwif_t *) m->private;
  38        const char      *name;
  39
  40        switch (hwif->chipset) {
  41        case ide_generic:       name = "generic";       break;
  42        case ide_pci:           name = "pci";           break;
  43        case ide_cmd640:        name = "cmd640";        break;
  44        case ide_dtc2278:       name = "dtc2278";       break;
  45        case ide_ali14xx:       name = "ali14xx";       break;
  46        case ide_qd65xx:        name = "qd65xx";        break;
  47        case ide_umc8672:       name = "umc8672";       break;
  48        case ide_ht6560b:       name = "ht6560b";       break;
  49        case ide_4drives:       name = "4drives";       break;
  50        case ide_pmac:          name = "mac-io";        break;
  51        case ide_au1xxx:        name = "au1xxx";        break;
  52        case ide_palm3710:      name = "palm3710";      break;
  53        case ide_acorn:         name = "acorn";         break;
  54        default:                name = "(unknown)";     break;
  55        }
  56        seq_printf(m, "%s\n", name);
  57        return 0;
  58}
  59
  60static int ide_mate_proc_show(struct seq_file *m, void *v)
  61{
  62        ide_hwif_t      *hwif = (ide_hwif_t *) m->private;
  63
  64        if (hwif && hwif->mate)
  65                seq_printf(m, "%s\n", hwif->mate->name);
  66        else
  67                seq_printf(m, "(none)\n");
  68        return 0;
  69}
  70
  71static int ide_channel_proc_show(struct seq_file *m, void *v)
  72{
  73        ide_hwif_t      *hwif = (ide_hwif_t *) m->private;
  74
  75        seq_printf(m, "%c\n", hwif->channel ? '1' : '0');
  76        return 0;
  77}
  78
  79static int ide_identify_proc_show(struct seq_file *m, void *v)
  80{
  81        ide_drive_t *drive = (ide_drive_t *)m->private;
  82        u8 *buf;
  83
  84        if (!drive) {
  85                seq_putc(m, '\n');
  86                return 0;
  87        }
  88
  89        buf = kmalloc(SECTOR_SIZE, GFP_KERNEL);
  90        if (!buf)
  91                return -ENOMEM;
  92        if (taskfile_lib_get_identify(drive, buf) == 0) {
  93                __le16 *val = (__le16 *)buf;
  94                int i;
  95
  96                for (i = 0; i < SECTOR_SIZE / 2; i++) {
  97                        seq_printf(m, "%04x%c", le16_to_cpu(val[i]),
  98                                        (i % 8) == 7 ? '\n' : ' ');
  99                }
 100        } else
 101                seq_putc(m, buf[0]);
 102        kfree(buf);
 103        return 0;
 104}
 105
 106/**
 107 *      ide_find_setting        -       find a specific setting
 108 *      @st: setting table pointer
 109 *      @name: setting name
 110 *
 111 *      Scan's the setting table for a matching entry and returns
 112 *      this or NULL if no entry is found. The caller must hold the
 113 *      setting semaphore
 114 */
 115
 116static
 117const struct ide_proc_devset *ide_find_setting(const struct ide_proc_devset *st,
 118                                               char *name)
 119{
 120        while (st->name) {
 121                if (strcmp(st->name, name) == 0)
 122                        break;
 123                st++;
 124        }
 125        return st->name ? st : NULL;
 126}
 127
 128/**
 129 *      ide_read_setting        -       read an IDE setting
 130 *      @drive: drive to read from
 131 *      @setting: drive setting
 132 *
 133 *      Read a drive setting and return the value. The caller
 134 *      must hold the ide_setting_mtx when making this call.
 135 *
 136 *      BUGS: the data return and error are the same return value
 137 *      so an error -EINVAL and true return of the same value cannot
 138 *      be told apart
 139 */
 140
 141static int ide_read_setting(ide_drive_t *drive,
 142                            const struct ide_proc_devset *setting)
 143{
 144        const struct ide_devset *ds = setting->setting;
 145        int val = -EINVAL;
 146
 147        if (ds->get)
 148                val = ds->get(drive);
 149
 150        return val;
 151}
 152
 153/**
 154 *      ide_write_setting       -       read an IDE setting
 155 *      @drive: drive to read from
 156 *      @setting: drive setting
 157 *      @val: value
 158 *
 159 *      Write a drive setting if it is possible. The caller
 160 *      must hold the ide_setting_mtx when making this call.
 161 *
 162 *      BUGS: the data return and error are the same return value
 163 *      so an error -EINVAL and true return of the same value cannot
 164 *      be told apart
 165 *
 166 *      FIXME:  This should be changed to enqueue a special request
 167 *      to the driver to change settings, and then wait on a sema for completion.
 168 *      The current scheme of polling is kludgy, though safe enough.
 169 */
 170
 171static int ide_write_setting(ide_drive_t *drive,
 172                             const struct ide_proc_devset *setting, int val)
 173{
 174        const struct ide_devset *ds = setting->setting;
 175
 176        if (!capable(CAP_SYS_ADMIN))
 177                return -EACCES;
 178        if (!ds->set)
 179                return -EPERM;
 180        if ((ds->flags & DS_SYNC)
 181            && (val < setting->min || val > setting->max))
 182                return -EINVAL;
 183        return ide_devset_execute(drive, ds, val);
 184}
 185
 186ide_devset_get(xfer_rate, current_speed);
 187
 188static int set_xfer_rate (ide_drive_t *drive, int arg)
 189{
 190        struct ide_cmd cmd;
 191
 192        if (arg < XFER_PIO_0 || arg > XFER_UDMA_6)
 193                return -EINVAL;
 194
 195        memset(&cmd, 0, sizeof(cmd));
 196        cmd.tf.command = ATA_CMD_SET_FEATURES;
 197        cmd.tf.feature = SETFEATURES_XFER;
 198        cmd.tf.nsect   = (u8)arg;
 199        cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT;
 200        cmd.valid.in.tf  = IDE_VALID_NSECT;
 201        cmd.tf_flags   = IDE_TFLAG_SET_XFER;
 202
 203        return ide_no_data_taskfile(drive, &cmd);
 204}
 205
 206ide_devset_rw(current_speed, xfer_rate);
 207ide_devset_rw_field(init_speed, init_speed);
 208ide_devset_rw_flag(nice1, IDE_DFLAG_NICE1);
 209ide_devset_ro_field(number, dn);
 210
 211static const struct ide_proc_devset ide_generic_settings[] = {
 212        IDE_PROC_DEVSET(current_speed, 0, 70),
 213        IDE_PROC_DEVSET(init_speed, 0, 70),
 214        IDE_PROC_DEVSET(io_32bit,  0, 1 + (SUPPORT_VLB_SYNC << 1)),
 215        IDE_PROC_DEVSET(keepsettings, 0, 1),
 216        IDE_PROC_DEVSET(nice1, 0, 1),
 217        IDE_PROC_DEVSET(number, 0, 3),
 218        IDE_PROC_DEVSET(pio_mode, 0, 255),
 219        IDE_PROC_DEVSET(unmaskirq, 0, 1),
 220        IDE_PROC_DEVSET(using_dma, 0, 1),
 221        { NULL },
 222};
 223
 224static void proc_ide_settings_warn(void)
 225{
 226        printk_once(KERN_WARNING "Warning: /proc/ide/hd?/settings interface is "
 227                            "obsolete, and will be removed soon!\n");
 228}
 229
 230static int ide_settings_proc_show(struct seq_file *m, void *v)
 231{
 232        const struct ide_proc_devset *setting, *g, *d;
 233        const struct ide_devset *ds;
 234        ide_drive_t     *drive = (ide_drive_t *) m->private;
 235        int             rc, mul_factor, div_factor;
 236
 237        proc_ide_settings_warn();
 238
 239        mutex_lock(&ide_setting_mtx);
 240        g = ide_generic_settings;
 241        d = drive->settings;
 242        seq_printf(m, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
 243        seq_printf(m, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
 244        while (g->name || (d && d->name)) {
 245                /* read settings in the alphabetical order */
 246                if (g->name && d && d->name) {
 247                        if (strcmp(d->name, g->name) < 0)
 248                                setting = d++;
 249                        else
 250                                setting = g++;
 251                } else if (d && d->name) {
 252                        setting = d++;
 253                } else
 254                        setting = g++;
 255                mul_factor = setting->mulf ? setting->mulf(drive) : 1;
 256                div_factor = setting->divf ? setting->divf(drive) : 1;
 257                seq_printf(m, "%-24s", setting->name);
 258                rc = ide_read_setting(drive, setting);
 259                if (rc >= 0)
 260                        seq_printf(m, "%-16d", rc * mul_factor / div_factor);
 261                else
 262                        seq_printf(m, "%-16s", "write-only");
 263                seq_printf(m, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor);
 264                ds = setting->setting;
 265                if (ds->get)
 266                        seq_printf(m, "r");
 267                if (ds->set)
 268                        seq_printf(m, "w");
 269                seq_printf(m, "\n");
 270        }
 271        mutex_unlock(&ide_setting_mtx);
 272        return 0;
 273}
 274
 275static int ide_settings_proc_open(struct inode *inode, struct file *file)
 276{
 277        return single_open(file, ide_settings_proc_show, PDE_DATA(inode));
 278}
 279
 280#define MAX_LEN 30
 281
 282static ssize_t ide_settings_proc_write(struct file *file, const char __user *buffer,
 283                                       size_t count, loff_t *pos)
 284{
 285        ide_drive_t     *drive = PDE_DATA(file_inode(file));
 286        char            name[MAX_LEN + 1];
 287        int             for_real = 0, mul_factor, div_factor;
 288        unsigned long   n;
 289
 290        const struct ide_proc_devset *setting;
 291        char *buf, *s;
 292
 293        if (!capable(CAP_SYS_ADMIN))
 294                return -EACCES;
 295
 296        proc_ide_settings_warn();
 297
 298        if (count >= PAGE_SIZE)
 299                return -EINVAL;
 300
 301        s = buf = (char *)__get_free_page(GFP_USER);
 302        if (!buf)
 303                return -ENOMEM;
 304
 305        if (copy_from_user(buf, buffer, count)) {
 306                free_page((unsigned long)buf);
 307                return -EFAULT;
 308        }
 309
 310        buf[count] = '\0';
 311
 312        /*
 313         * Skip over leading whitespace
 314         */
 315        while (count && isspace(*s)) {
 316                --count;
 317                ++s;
 318        }
 319        /*
 320         * Do one full pass to verify all parameters,
 321         * then do another to actually write the new settings.
 322         */
 323        do {
 324                char *p = s;
 325                n = count;
 326                while (n > 0) {
 327                        unsigned val;
 328                        char *q = p;
 329
 330                        while (n > 0 && *p != ':') {
 331                                --n;
 332                                p++;
 333                        }
 334                        if (*p != ':')
 335                                goto parse_error;
 336                        if (p - q > MAX_LEN)
 337                                goto parse_error;
 338                        memcpy(name, q, p - q);
 339                        name[p - q] = 0;
 340
 341                        if (n > 0) {
 342                                --n;
 343                                p++;
 344                        } else
 345                                goto parse_error;
 346
 347                        val = simple_strtoul(p, &q, 10);
 348                        n -= q - p;
 349                        p = q;
 350                        if (n > 0 && !isspace(*p))
 351                                goto parse_error;
 352                        while (n > 0 && isspace(*p)) {
 353                                --n;
 354                                ++p;
 355                        }
 356
 357                        mutex_lock(&ide_setting_mtx);
 358                        /* generic settings first, then driver specific ones */
 359                        setting = ide_find_setting(ide_generic_settings, name);
 360                        if (!setting) {
 361                                if (drive->settings)
 362                                        setting = ide_find_setting(drive->settings, name);
 363                                if (!setting) {
 364                                        mutex_unlock(&ide_setting_mtx);
 365                                        goto parse_error;
 366                                }
 367                        }
 368                        if (for_real) {
 369                                mul_factor = setting->mulf ? setting->mulf(drive) : 1;
 370                                div_factor = setting->divf ? setting->divf(drive) : 1;
 371                                ide_write_setting(drive, setting, val * div_factor / mul_factor);
 372                        }
 373                        mutex_unlock(&ide_setting_mtx);
 374                }
 375        } while (!for_real++);
 376        free_page((unsigned long)buf);
 377        return count;
 378parse_error:
 379        free_page((unsigned long)buf);
 380        printk("%s(): parse error\n", __func__);
 381        return -EINVAL;
 382}
 383
 384static const struct proc_ops ide_settings_proc_ops = {
 385        .proc_open      = ide_settings_proc_open,
 386        .proc_read      = seq_read,
 387        .proc_lseek     = seq_lseek,
 388        .proc_release   = single_release,
 389        .proc_write     = ide_settings_proc_write,
 390};
 391
 392int ide_capacity_proc_show(struct seq_file *m, void *v)
 393{
 394        seq_printf(m, "%llu\n", (long long)0x7fffffff);
 395        return 0;
 396}
 397EXPORT_SYMBOL_GPL(ide_capacity_proc_show);
 398
 399int ide_geometry_proc_show(struct seq_file *m, void *v)
 400{
 401        ide_drive_t     *drive = (ide_drive_t *) m->private;
 402
 403        seq_printf(m, "physical     %d/%d/%d\n",
 404                        drive->cyl, drive->head, drive->sect);
 405        seq_printf(m, "logical      %d/%d/%d\n",
 406                        drive->bios_cyl, drive->bios_head, drive->bios_sect);
 407        return 0;
 408}
 409EXPORT_SYMBOL(ide_geometry_proc_show);
 410
 411static int ide_dmodel_proc_show(struct seq_file *seq, void *v)
 412{
 413        ide_drive_t     *drive = (ide_drive_t *) seq->private;
 414        char            *m = (char *)&drive->id[ATA_ID_PROD];
 415
 416        seq_printf(seq, "%.40s\n", m[0] ? m : "(none)");
 417        return 0;
 418}
 419
 420static int ide_driver_proc_show(struct seq_file *m, void *v)
 421{
 422        ide_drive_t             *drive = (ide_drive_t *)m->private;
 423        struct device           *dev = &drive->gendev;
 424        struct ide_driver       *ide_drv;
 425
 426        if (dev->driver) {
 427                ide_drv = to_ide_driver(dev->driver);
 428                seq_printf(m, "%s version %s\n",
 429                                dev->driver->name, ide_drv->version);
 430        } else
 431                seq_printf(m, "ide-default version 0.9.newide\n");
 432        return 0;
 433}
 434
 435static int ide_media_proc_show(struct seq_file *m, void *v)
 436{
 437        ide_drive_t     *drive = (ide_drive_t *) m->private;
 438        const char      *media;
 439
 440        switch (drive->media) {
 441        case ide_disk:          media = "disk\n";       break;
 442        case ide_cdrom:         media = "cdrom\n";      break;
 443        case ide_tape:          media = "tape\n";       break;
 444        case ide_floppy:        media = "floppy\n";     break;
 445        case ide_optical:       media = "optical\n";    break;
 446        default:                media = "UNKNOWN\n";    break;
 447        }
 448        seq_puts(m, media);
 449        return 0;
 450}
 451
 452static int ide_media_proc_open(struct inode *inode, struct file *file)
 453{
 454        return single_open(file, ide_media_proc_show, PDE_DATA(inode));
 455}
 456
 457static const struct file_operations ide_media_proc_fops = {
 458        .owner          = THIS_MODULE,
 459        .open           = ide_media_proc_open,
 460        .read           = seq_read,
 461        .llseek         = seq_lseek,
 462        .release        = single_release,
 463};
 464
 465static ide_proc_entry_t generic_drive_entries[] = {
 466        { "driver",     S_IFREG|S_IRUGO,         ide_driver_proc_show   },
 467        { "identify",   S_IFREG|S_IRUSR,         ide_identify_proc_show },
 468        { "media",      S_IFREG|S_IRUGO,         ide_media_proc_show    },
 469        { "model",      S_IFREG|S_IRUGO,         ide_dmodel_proc_show   },
 470        {}
 471};
 472
 473static void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
 474{
 475        struct proc_dir_entry *ent;
 476
 477        if (!dir || !p)
 478                return;
 479        while (p->name != NULL) {
 480                ent = proc_create_single_data(p->name, p->mode, dir, p->show, data);
 481                if (!ent) return;
 482                p++;
 483        }
 484}
 485
 486static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
 487{
 488        if (!dir || !p)
 489                return;
 490        while (p->name != NULL) {
 491                remove_proc_entry(p->name, dir);
 492                p++;
 493        }
 494}
 495
 496void ide_proc_register_driver(ide_drive_t *drive, struct ide_driver *driver)
 497{
 498        mutex_lock(&ide_setting_mtx);
 499        drive->settings = driver->proc_devsets(drive);
 500        mutex_unlock(&ide_setting_mtx);
 501
 502        ide_add_proc_entries(drive->proc, driver->proc_entries(drive), drive);
 503}
 504
 505EXPORT_SYMBOL(ide_proc_register_driver);
 506
 507/**
 508 *      ide_proc_unregister_driver      -       remove driver specific data
 509 *      @drive: drive
 510 *      @driver: driver
 511 *
 512 *      Clean up the driver specific /proc files and IDE settings
 513 *      for a given drive.
 514 *
 515 *      Takes ide_setting_mtx.
 516 */
 517
 518void ide_proc_unregister_driver(ide_drive_t *drive, struct ide_driver *driver)
 519{
 520        ide_remove_proc_entries(drive->proc, driver->proc_entries(drive));
 521
 522        mutex_lock(&ide_setting_mtx);
 523        /*
 524         * ide_setting_mtx protects both the settings list and the use
 525         * of settings (we cannot take a setting out that is being used).
 526         */
 527        drive->settings = NULL;
 528        mutex_unlock(&ide_setting_mtx);
 529}
 530EXPORT_SYMBOL(ide_proc_unregister_driver);
 531
 532void ide_proc_port_register_devices(ide_hwif_t *hwif)
 533{
 534        struct proc_dir_entry *ent;
 535        struct proc_dir_entry *parent = hwif->proc;
 536        ide_drive_t *drive;
 537        char name[64];
 538        int i;
 539
 540        ide_port_for_each_dev(i, drive, hwif) {
 541                if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
 542                        continue;
 543
 544                drive->proc = proc_mkdir(drive->name, parent);
 545                if (drive->proc) {
 546                        ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
 547                        proc_create_data("settings", S_IFREG|S_IRUSR|S_IWUSR,
 548                                        drive->proc, &ide_settings_proc_ops,
 549                                        drive);
 550                }
 551                sprintf(name, "ide%d/%s", (drive->name[2]-'a')/2, drive->name);
 552                ent = proc_symlink(drive->name, proc_ide_root, name);
 553                if (!ent) return;
 554        }
 555}
 556
 557void ide_proc_unregister_device(ide_drive_t *drive)
 558{
 559        if (drive->proc) {
 560                remove_proc_entry("settings", drive->proc);
 561                ide_remove_proc_entries(drive->proc, generic_drive_entries);
 562                remove_proc_entry(drive->name, proc_ide_root);
 563                remove_proc_entry(drive->name, drive->hwif->proc);
 564                drive->proc = NULL;
 565        }
 566}
 567
 568static ide_proc_entry_t hwif_entries[] = {
 569        { "channel",    S_IFREG|S_IRUGO,        ide_channel_proc_show   },
 570        { "mate",       S_IFREG|S_IRUGO,        ide_mate_proc_show      },
 571        { "model",      S_IFREG|S_IRUGO,        ide_imodel_proc_show    },
 572        {}
 573};
 574
 575void ide_proc_register_port(ide_hwif_t *hwif)
 576{
 577        if (!hwif->proc) {
 578                hwif->proc = proc_mkdir(hwif->name, proc_ide_root);
 579
 580                if (!hwif->proc)
 581                        return;
 582
 583                ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
 584        }
 585}
 586
 587void ide_proc_unregister_port(ide_hwif_t *hwif)
 588{
 589        if (hwif->proc) {
 590                ide_remove_proc_entries(hwif->proc, hwif_entries);
 591                remove_proc_entry(hwif->name, proc_ide_root);
 592                hwif->proc = NULL;
 593        }
 594}
 595
 596static int proc_print_driver(struct device_driver *drv, void *data)
 597{
 598        struct ide_driver *ide_drv = to_ide_driver(drv);
 599        struct seq_file *s = data;
 600
 601        seq_printf(s, "%s version %s\n", drv->name, ide_drv->version);
 602
 603        return 0;
 604}
 605
 606static int ide_drivers_show(struct seq_file *s, void *p)
 607{
 608        int err;
 609
 610        err = bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver);
 611        if (err < 0)
 612                printk(KERN_WARNING "IDE: %s: bus_for_each_drv error: %d\n",
 613                        __func__, err);
 614        return 0;
 615}
 616
 617DEFINE_PROC_SHOW_ATTRIBUTE(ide_drivers);
 618
 619void proc_ide_create(void)
 620{
 621        proc_ide_root = proc_mkdir("ide", NULL);
 622
 623        if (!proc_ide_root)
 624                return;
 625
 626        proc_create("drivers", 0, proc_ide_root, &ide_drivers_proc_ops);
 627}
 628
 629void proc_ide_destroy(void)
 630{
 631        remove_proc_entry("drivers", proc_ide_root);
 632        remove_proc_entry("ide", NULL);
 633}
 634