at v2.6.21 575 lines 14 kB view raw
1/* 2 * linux/drivers/ide/ide-proc.c Version 1.05 Mar 05, 2003 3 * 4 * Copyright (C) 1997-1998 Mark Lord 5 * Copyright (C) 2003 Red Hat <alan@redhat.com> 6 */ 7 8/* 9 * This is the /proc/ide/ filesystem implementation. 10 * 11 * Drive/Driver settings can be retrieved by reading the drive's 12 * "settings" files. e.g. "cat /proc/ide0/hda/settings" 13 * To write a new value "val" into a specific setting "name", use: 14 * echo "name:val" >/proc/ide/ide0/hda/settings 15 * 16 * Also useful, "cat /proc/ide0/hda/[identify, smart_values, 17 * smart_thresholds, capabilities]" will issue an IDENTIFY / 18 * PACKET_IDENTIFY / SMART_READ_VALUES / SMART_READ_THRESHOLDS / 19 * SENSE CAPABILITIES command to /dev/hda, and then dump out the 20 * returned data as 256 16-bit words. The "hdparm" utility will 21 * be updated someday soon to use this mechanism. 22 * 23 */ 24 25#include <linux/module.h> 26 27#include <asm/uaccess.h> 28#include <linux/errno.h> 29#include <linux/proc_fs.h> 30#include <linux/stat.h> 31#include <linux/mm.h> 32#include <linux/pci.h> 33#include <linux/ctype.h> 34#include <linux/hdreg.h> 35#include <linux/ide.h> 36#include <linux/seq_file.h> 37 38#include <asm/io.h> 39 40static int proc_ide_read_imodel 41 (char *page, char **start, off_t off, int count, int *eof, void *data) 42{ 43 ide_hwif_t *hwif = (ide_hwif_t *) data; 44 int len; 45 const char *name; 46 47 /* 48 * Neither ide_unknown nor ide_forced should be set at this point. 49 */ 50 switch (hwif->chipset) { 51 case ide_generic: name = "generic"; break; 52 case ide_pci: name = "pci"; break; 53 case ide_cmd640: name = "cmd640"; break; 54 case ide_dtc2278: name = "dtc2278"; break; 55 case ide_ali14xx: name = "ali14xx"; break; 56 case ide_qd65xx: name = "qd65xx"; break; 57 case ide_umc8672: name = "umc8672"; break; 58 case ide_ht6560b: name = "ht6560b"; break; 59 case ide_rz1000: name = "rz1000"; break; 60 case ide_trm290: name = "trm290"; break; 61 case ide_cmd646: name = "cmd646"; break; 62 case ide_cy82c693: name = "cy82c693"; break; 63 case ide_4drives: name = "4drives"; break; 64 case ide_pmac: name = "mac-io"; break; 65 case ide_au1xxx: name = "au1xxx"; break; 66 default: name = "(unknown)"; break; 67 } 68 len = sprintf(page, "%s\n", name); 69 PROC_IDE_READ_RETURN(page,start,off,count,eof,len); 70} 71 72static int proc_ide_read_mate 73 (char *page, char **start, off_t off, int count, int *eof, void *data) 74{ 75 ide_hwif_t *hwif = (ide_hwif_t *) data; 76 int len; 77 78 if (hwif && hwif->mate && hwif->mate->present) 79 len = sprintf(page, "%s\n", hwif->mate->name); 80 else 81 len = sprintf(page, "(none)\n"); 82 PROC_IDE_READ_RETURN(page,start,off,count,eof,len); 83} 84 85static int proc_ide_read_channel 86 (char *page, char **start, off_t off, int count, int *eof, void *data) 87{ 88 ide_hwif_t *hwif = (ide_hwif_t *) data; 89 int len; 90 91 page[0] = hwif->channel ? '1' : '0'; 92 page[1] = '\n'; 93 len = 2; 94 PROC_IDE_READ_RETURN(page,start,off,count,eof,len); 95} 96 97static int proc_ide_read_identify 98 (char *page, char **start, off_t off, int count, int *eof, void *data) 99{ 100 ide_drive_t *drive = (ide_drive_t *)data; 101 int len = 0, i = 0; 102 int err = 0; 103 104 len = sprintf(page, "\n"); 105 106 if (drive) { 107 unsigned short *val = (unsigned short *) page; 108 109 err = taskfile_lib_get_identify(drive, page); 110 if (!err) { 111 char *out = ((char *)page) + (SECTOR_WORDS * 4); 112 page = out; 113 do { 114 out += sprintf(out, "%04x%c", 115 le16_to_cpu(*val), (++i & 7) ? ' ' : '\n'); 116 val += 1; 117 } while (i < (SECTOR_WORDS * 2)); 118 len = out - page; 119 } 120 } 121 PROC_IDE_READ_RETURN(page,start,off,count,eof,len); 122} 123 124static void proc_ide_settings_warn(void) 125{ 126 static int warned = 0; 127 128 if (warned) 129 return; 130 131 printk(KERN_WARNING "Warning: /proc/ide/hd?/settings interface is " 132 "obsolete, and will be removed soon!\n"); 133 warned = 1; 134} 135 136static int proc_ide_read_settings 137 (char *page, char **start, off_t off, int count, int *eof, void *data) 138{ 139 ide_drive_t *drive = (ide_drive_t *) data; 140 ide_settings_t *setting = (ide_settings_t *) drive->settings; 141 char *out = page; 142 int len, rc, mul_factor, div_factor; 143 144 proc_ide_settings_warn(); 145 146 down(&ide_setting_sem); 147 out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n"); 148 out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n"); 149 while(setting) { 150 mul_factor = setting->mul_factor; 151 div_factor = setting->div_factor; 152 out += sprintf(out, "%-24s", setting->name); 153 if ((rc = ide_read_setting(drive, setting)) >= 0) 154 out += sprintf(out, "%-16d", rc * mul_factor / div_factor); 155 else 156 out += sprintf(out, "%-16s", "write-only"); 157 out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor); 158 if (setting->rw & SETTING_READ) 159 out += sprintf(out, "r"); 160 if (setting->rw & SETTING_WRITE) 161 out += sprintf(out, "w"); 162 out += sprintf(out, "\n"); 163 setting = setting->next; 164 } 165 len = out - page; 166 up(&ide_setting_sem); 167 PROC_IDE_READ_RETURN(page,start,off,count,eof,len); 168} 169 170#define MAX_LEN 30 171 172static int proc_ide_write_settings(struct file *file, const char __user *buffer, 173 unsigned long count, void *data) 174{ 175 ide_drive_t *drive = (ide_drive_t *) data; 176 char name[MAX_LEN + 1]; 177 int for_real = 0; 178 unsigned long n; 179 ide_settings_t *setting; 180 char *buf, *s; 181 182 if (!capable(CAP_SYS_ADMIN)) 183 return -EACCES; 184 185 proc_ide_settings_warn(); 186 187 if (count >= PAGE_SIZE) 188 return -EINVAL; 189 190 s = buf = (char *)__get_free_page(GFP_USER); 191 if (!buf) 192 return -ENOMEM; 193 194 if (copy_from_user(buf, buffer, count)) { 195 free_page((unsigned long)buf); 196 return -EFAULT; 197 } 198 199 buf[count] = '\0'; 200 201 /* 202 * Skip over leading whitespace 203 */ 204 while (count && isspace(*s)) { 205 --count; 206 ++s; 207 } 208 /* 209 * Do one full pass to verify all parameters, 210 * then do another to actually write the new settings. 211 */ 212 do { 213 char *p = s; 214 n = count; 215 while (n > 0) { 216 unsigned val; 217 char *q = p; 218 219 while (n > 0 && *p != ':') { 220 --n; 221 p++; 222 } 223 if (*p != ':') 224 goto parse_error; 225 if (p - q > MAX_LEN) 226 goto parse_error; 227 memcpy(name, q, p - q); 228 name[p - q] = 0; 229 230 if (n > 0) { 231 --n; 232 p++; 233 } else 234 goto parse_error; 235 236 val = simple_strtoul(p, &q, 10); 237 n -= q - p; 238 p = q; 239 if (n > 0 && !isspace(*p)) 240 goto parse_error; 241 while (n > 0 && isspace(*p)) { 242 --n; 243 ++p; 244 } 245 246 down(&ide_setting_sem); 247 setting = ide_find_setting_by_name(drive, name); 248 if (!setting) 249 { 250 up(&ide_setting_sem); 251 goto parse_error; 252 } 253 if (for_real) 254 ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor); 255 up(&ide_setting_sem); 256 } 257 } while (!for_real++); 258 free_page((unsigned long)buf); 259 return count; 260parse_error: 261 free_page((unsigned long)buf); 262 printk("proc_ide_write_settings(): parse error\n"); 263 return -EINVAL; 264} 265 266int proc_ide_read_capacity 267 (char *page, char **start, off_t off, int count, int *eof, void *data) 268{ 269 int len = sprintf(page,"%llu\n", (long long)0x7fffffff); 270 PROC_IDE_READ_RETURN(page,start,off,count,eof,len); 271} 272 273EXPORT_SYMBOL_GPL(proc_ide_read_capacity); 274 275int proc_ide_read_geometry 276 (char *page, char **start, off_t off, int count, int *eof, void *data) 277{ 278 ide_drive_t *drive = (ide_drive_t *) data; 279 char *out = page; 280 int len; 281 282 out += sprintf(out,"physical %d/%d/%d\n", 283 drive->cyl, drive->head, drive->sect); 284 out += sprintf(out,"logical %d/%d/%d\n", 285 drive->bios_cyl, drive->bios_head, drive->bios_sect); 286 287 len = out - page; 288 PROC_IDE_READ_RETURN(page,start,off,count,eof,len); 289} 290 291EXPORT_SYMBOL(proc_ide_read_geometry); 292 293static int proc_ide_read_dmodel 294 (char *page, char **start, off_t off, int count, int *eof, void *data) 295{ 296 ide_drive_t *drive = (ide_drive_t *) data; 297 struct hd_driveid *id = drive->id; 298 int len; 299 300 len = sprintf(page, "%.40s\n", 301 (id && id->model[0]) ? (char *)id->model : "(none)"); 302 PROC_IDE_READ_RETURN(page,start,off,count,eof,len); 303} 304 305static int proc_ide_read_driver 306 (char *page, char **start, off_t off, int count, int *eof, void *data) 307{ 308 ide_drive_t *drive = (ide_drive_t *) data; 309 struct device *dev = &drive->gendev; 310 ide_driver_t *ide_drv; 311 int len; 312 313 down_read(&dev->bus->subsys.rwsem); 314 if (dev->driver) { 315 ide_drv = container_of(dev->driver, ide_driver_t, gen_driver); 316 len = sprintf(page, "%s version %s\n", 317 dev->driver->name, ide_drv->version); 318 } else 319 len = sprintf(page, "ide-default version 0.9.newide\n"); 320 up_read(&dev->bus->subsys.rwsem); 321 PROC_IDE_READ_RETURN(page,start,off,count,eof,len); 322} 323 324static int ide_replace_subdriver(ide_drive_t *drive, const char *driver) 325{ 326 struct device *dev = &drive->gendev; 327 int ret = 1; 328 int err; 329 330 down_write(&dev->bus->subsys.rwsem); 331 device_release_driver(dev); 332 /* FIXME: device can still be in use by previous driver */ 333 strlcpy(drive->driver_req, driver, sizeof(drive->driver_req)); 334 err = device_attach(dev); 335 if (err < 0) 336 printk(KERN_WARNING "IDE: %s: device_attach error: %d\n", 337 __FUNCTION__, err); 338 drive->driver_req[0] = 0; 339 if (dev->driver == NULL) { 340 err = device_attach(dev); 341 if (err < 0) 342 printk(KERN_WARNING 343 "IDE: %s: device_attach(2) error: %d\n", 344 __FUNCTION__, err); 345 } 346 if (dev->driver && !strcmp(dev->driver->name, driver)) 347 ret = 0; 348 up_write(&dev->bus->subsys.rwsem); 349 350 return ret; 351} 352 353static int proc_ide_write_driver 354 (struct file *file, const char __user *buffer, unsigned long count, void *data) 355{ 356 ide_drive_t *drive = (ide_drive_t *) data; 357 char name[32]; 358 359 if (!capable(CAP_SYS_ADMIN)) 360 return -EACCES; 361 if (count > 31) 362 count = 31; 363 if (copy_from_user(name, buffer, count)) 364 return -EFAULT; 365 name[count] = '\0'; 366 if (ide_replace_subdriver(drive, name)) 367 return -EINVAL; 368 return count; 369} 370 371static int proc_ide_read_media 372 (char *page, char **start, off_t off, int count, int *eof, void *data) 373{ 374 ide_drive_t *drive = (ide_drive_t *) data; 375 const char *media; 376 int len; 377 378 switch (drive->media) { 379 case ide_disk: media = "disk\n"; 380 break; 381 case ide_cdrom: media = "cdrom\n"; 382 break; 383 case ide_tape: media = "tape\n"; 384 break; 385 case ide_floppy:media = "floppy\n"; 386 break; 387 case ide_optical:media = "optical\n"; 388 break; 389 default: media = "UNKNOWN\n"; 390 break; 391 } 392 strcpy(page,media); 393 len = strlen(media); 394 PROC_IDE_READ_RETURN(page,start,off,count,eof,len); 395} 396 397static ide_proc_entry_t generic_drive_entries[] = { 398 { "driver", S_IFREG|S_IRUGO, proc_ide_read_driver, proc_ide_write_driver }, 399 { "identify", S_IFREG|S_IRUSR, proc_ide_read_identify, NULL }, 400 { "media", S_IFREG|S_IRUGO, proc_ide_read_media, NULL }, 401 { "model", S_IFREG|S_IRUGO, proc_ide_read_dmodel, NULL }, 402 { "settings", S_IFREG|S_IRUSR|S_IWUSR,proc_ide_read_settings, proc_ide_write_settings }, 403 { NULL, 0, NULL, NULL } 404}; 405 406void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data) 407{ 408 struct proc_dir_entry *ent; 409 410 if (!dir || !p) 411 return; 412 while (p->name != NULL) { 413 ent = create_proc_entry(p->name, p->mode, dir); 414 if (!ent) return; 415 ent->data = data; 416 ent->read_proc = p->read_proc; 417 ent->write_proc = p->write_proc; 418 p++; 419 } 420} 421 422void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p) 423{ 424 if (!dir || !p) 425 return; 426 while (p->name != NULL) { 427 remove_proc_entry(p->name, dir); 428 p++; 429 } 430} 431 432static void create_proc_ide_drives(ide_hwif_t *hwif) 433{ 434 int d; 435 struct proc_dir_entry *ent; 436 struct proc_dir_entry *parent = hwif->proc; 437 char name[64]; 438 439 for (d = 0; d < MAX_DRIVES; d++) { 440 ide_drive_t *drive = &hwif->drives[d]; 441 442 if (!drive->present) 443 continue; 444 if (drive->proc) 445 continue; 446 447 drive->proc = proc_mkdir(drive->name, parent); 448 if (drive->proc) 449 ide_add_proc_entries(drive->proc, generic_drive_entries, drive); 450 sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name); 451 ent = proc_symlink(drive->name, proc_ide_root, name); 452 if (!ent) return; 453 } 454} 455 456static void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive) 457{ 458 if (drive->proc) { 459 ide_remove_proc_entries(drive->proc, generic_drive_entries); 460 remove_proc_entry(drive->name, proc_ide_root); 461 remove_proc_entry(drive->name, hwif->proc); 462 drive->proc = NULL; 463 } 464} 465 466static void destroy_proc_ide_drives(ide_hwif_t *hwif) 467{ 468 int d; 469 470 for (d = 0; d < MAX_DRIVES; d++) { 471 ide_drive_t *drive = &hwif->drives[d]; 472 if (drive->proc) 473 destroy_proc_ide_device(hwif, drive); 474 } 475} 476 477static ide_proc_entry_t hwif_entries[] = { 478 { "channel", S_IFREG|S_IRUGO, proc_ide_read_channel, NULL }, 479 { "mate", S_IFREG|S_IRUGO, proc_ide_read_mate, NULL }, 480 { "model", S_IFREG|S_IRUGO, proc_ide_read_imodel, NULL }, 481 { NULL, 0, NULL, NULL } 482}; 483 484void create_proc_ide_interfaces(void) 485{ 486 int h; 487 488 for (h = 0; h < MAX_HWIFS; h++) { 489 ide_hwif_t *hwif = &ide_hwifs[h]; 490 491 if (!hwif->present) 492 continue; 493 if (!hwif->proc) { 494 hwif->proc = proc_mkdir(hwif->name, proc_ide_root); 495 if (!hwif->proc) 496 return; 497 ide_add_proc_entries(hwif->proc, hwif_entries, hwif); 498 } 499 create_proc_ide_drives(hwif); 500 } 501} 502 503EXPORT_SYMBOL(create_proc_ide_interfaces); 504 505#ifdef CONFIG_BLK_DEV_IDEPCI 506void ide_pci_create_host_proc(const char *name, get_info_t *get_info) 507{ 508 create_proc_info_entry(name, 0, proc_ide_root, get_info); 509} 510 511EXPORT_SYMBOL_GPL(ide_pci_create_host_proc); 512#endif 513 514void destroy_proc_ide_interface(ide_hwif_t *hwif) 515{ 516 if (hwif->proc) { 517 destroy_proc_ide_drives(hwif); 518 ide_remove_proc_entries(hwif->proc, hwif_entries); 519 remove_proc_entry(hwif->name, proc_ide_root); 520 hwif->proc = NULL; 521 } 522} 523 524static int proc_print_driver(struct device_driver *drv, void *data) 525{ 526 ide_driver_t *ide_drv = container_of(drv, ide_driver_t, gen_driver); 527 struct seq_file *s = data; 528 529 seq_printf(s, "%s version %s\n", drv->name, ide_drv->version); 530 531 return 0; 532} 533 534static int ide_drivers_show(struct seq_file *s, void *p) 535{ 536 int err; 537 538 err = bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver); 539 if (err < 0) 540 printk(KERN_WARNING "IDE: %s: bus_for_each_drv error: %d\n", 541 __FUNCTION__, err); 542 return 0; 543} 544 545static int ide_drivers_open(struct inode *inode, struct file *file) 546{ 547 return single_open(file, &ide_drivers_show, NULL); 548} 549 550static const struct file_operations ide_drivers_operations = { 551 .open = ide_drivers_open, 552 .read = seq_read, 553 .llseek = seq_lseek, 554 .release = single_release, 555}; 556 557void proc_ide_create(void) 558{ 559 struct proc_dir_entry *entry; 560 561 if (!proc_ide_root) 562 return; 563 564 create_proc_ide_interfaces(); 565 566 entry = create_proc_entry("drivers", 0, proc_ide_root); 567 if (entry) 568 entry->proc_fops = &ide_drivers_operations; 569} 570 571void proc_ide_destroy(void) 572{ 573 remove_proc_entry("drivers", proc_ide_root); 574 remove_proc_entry("ide", NULL); 575}