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  * The major reason this exists is to provide sufficient access
12  * to driver and config data, such that user-mode programs can
13  * be developed to handle chipset tuning for most PCI interfaces.
14  * This should provide better utilities, and less kernel bloat.
15  *
16  * The entire pci config space for a PCI interface chipset can be
17  * retrieved by just reading it.  e.g.    "cat /proc/ide3/config"
18  *
19  * To modify registers *safely*, do something like:
20  *   echo "P40:88" >/proc/ide/ide3/config
21  * That expression writes 0x88 to pci config register 0x40
22  * on the chip which controls ide3.  Multiple tuples can be issued,
23  * and the writes will be completed as an atomic set:
24  *   echo "P40:88 P41:35 P42:00 P43:00" >/proc/ide/ide3/config
25  *
26  * All numbers must be specified using pairs of ascii hex digits.
27  * It is important to note that these writes will be performed
28  * after waiting for the IDE controller (both interfaces)
29  * to be completely idle, to ensure no corruption of I/O in progress.
30  *
31  * Non-PCI registers can also be written, using "R" in place of "P"
32  * in the above examples.  The size of the port transfer is determined
33  * by the number of pairs of hex digits given for the data.  If a two
34  * digit value is given, the write will be a byte operation; if four
35  * digits are used, the write will be performed as a 16-bit operation;
36  * and if eight digits are specified, a 32-bit "dword" write will be
37  * performed.  Odd numbers of digits are not permitted.
38  *
39  * If there is an error *anywhere* in the string of registers/data
40  * then *none* of the writes will be performed.
41  *
42  * Drive/Driver settings can be retrieved by reading the drive's
43  * "settings" files.  e.g.    "cat /proc/ide0/hda/settings"
44  * To write a new value "val" into a specific setting "name", use:
45  *   echo "name:val" >/proc/ide/ide0/hda/settings
46  *
47  * Also useful, "cat /proc/ide0/hda/[identify, smart_values,
48  * smart_thresholds, capabilities]" will issue an IDENTIFY /
49  * PACKET_IDENTIFY / SMART_READ_VALUES / SMART_READ_THRESHOLDS /
50  * SENSE CAPABILITIES command to /dev/hda, and then dump out the
51  * returned data as 256 16-bit words.  The "hdparm" utility will
52  * be updated someday soon to use this mechanism.
53  *
54  * Feel free to develop and distribute fancy GUI configuration
55  * utilities for your favorite PCI chipsets.  I'll be working on
56  * one for the Promise 20246 someday soon.  -ml
57  *
58  */
59 
60 #include <linux/config.h>
61 #define __NO_VERSION__
62 #include <linux/module.h>
63 
64 #include <asm/uaccess.h>
65 #include <linux/errno.h>
66 #include <linux/sched.h>
67 #include <linux/proc_fs.h>
68 #include <linux/stat.h>
69 #include <linux/mm.h>
70 #include <linux/pci.h>
71 #include <linux/ctype.h>
72 #include <linux/hdreg.h>
73 #include <linux/ide.h>
74 
75 #include <asm/io.h>
76 
77 #ifdef CONFIG_ALL_PPC
78 #include <asm/prom.h>
79 #include <asm/pci-bridge.h>
80 #endif
81 
82 #ifndef MIN
83 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
84 #endif
85 
ide_getxdigit(char c)86 static int ide_getxdigit(char c)
87 {
88 	int digit;
89 	if (isdigit(c))
90 		digit = c - '0';
91 	else if (isxdigit(c))
92 		digit = tolower(c) - 'a' + 10;
93 	else
94 		digit = -1;
95 	return digit;
96 }
97 
xx_xx_parse_error(const char * data,unsigned long len,const char * msg)98 static int xx_xx_parse_error (const char *data, unsigned long len, const char *msg)
99 {
100 	char errbuf[16];
101 	int i;
102 	if (len >= sizeof(errbuf))
103 		len = sizeof(errbuf) - 1;
104 	for (i = 0; i < len; ++i) {
105 		char c = data[i];
106 		if (!c || c == '\n')
107 			c = '\0';
108 		else if (iscntrl(c))
109 			c = '?';
110 		errbuf[i] = c;
111 	}
112 	errbuf[i] = '\0';
113 	printk("proc_ide: error: %s: '%s'\n", msg, errbuf);
114 	return -EINVAL;
115 }
116 
117 static struct proc_dir_entry * proc_ide_root = NULL;
118 
119 #ifdef CONFIG_BLK_DEV_IDEPCI
120 #include <linux/delay.h>
121 /*
122  * This is the list of registered PCI chipset driver data structures.
123  */
124 static ide_pci_host_proc_t * ide_pci_host_proc_list;
125 
126 #endif /* CONFIG_BLK_DEV_IDEPCI */
127 
128 #undef __PROC_HELL
129 
proc_ide_write_config(struct file * file,const char * buffer,unsigned long count,void * data)130 static int proc_ide_write_config
131 	(struct file *file, const char *buffer, unsigned long count, void *data)
132 {
133 	ide_hwif_t	*hwif = (ide_hwif_t *)data;
134 	int		for_real = 0;
135 	unsigned long	startn = 0, n, flags;
136 	const char	*start = NULL, *msg = NULL;
137 
138 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
139 		return -EACCES;
140 	/*
141 	 * Skip over leading whitespace
142 	 */
143 	while (count && isspace(*buffer)) {
144 		--count;
145 		++buffer;
146 	}
147 	/*
148 	 * Do one full pass to verify all parameters,
149 	 * then do another to actually write the regs.
150 	 */
151 #ifndef __PROC_HELL
152 	save_flags(flags);	/* all CPUs */
153 #else
154 	spin_lock_irqsave(&io_request_lock, flags);
155 #endif
156 	do {
157 		const char *p;
158 		if (for_real) {
159 			unsigned long timeout = jiffies + (3 * HZ);
160 			ide_hwgroup_t *mygroup = (ide_hwgroup_t *)(hwif->hwgroup);
161 			ide_hwgroup_t *mategroup = NULL;
162 			if (hwif->mate && hwif->mate->hwgroup)
163 				mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup);
164 #ifndef __PROC_HELL
165 			cli();	/* all CPUs; ensure all writes are done together */
166 #else
167 			spin_lock_irqsave(&io_request_lock, flags);
168 #endif
169 			while (mygroup->busy ||
170 			       (mategroup && mategroup->busy)) {
171 #ifndef __PROC_HELL
172 				sti();	/* all CPUs */
173 #else
174 				spin_unlock_irqrestore(&io_request_lock, flags);
175 #endif
176 				if (time_after(jiffies, timeout)) {
177 					printk("/proc/ide/%s/config: channel(s) busy, cannot write\n", hwif->name);
178 #ifndef __PROC_HELL
179 					restore_flags(flags);	/* all CPUs */
180 #else
181 					spin_unlock_irqrestore(&io_request_lock, flags);
182 #endif
183 					return -EBUSY;
184 				}
185 #ifndef __PROC_HELL
186 				cli();	/* all CPUs */
187 #else
188 				spin_lock_irqsave(&io_request_lock, flags);
189 #endif
190 			}
191 		}
192 		p = buffer;
193 		n = count;
194 		while (n > 0) {
195 			int d, digits;
196 			unsigned int reg = 0, val = 0, is_pci;
197 			start = p;
198 			startn = n--;
199 			switch (*p++) {
200 				case 'R':	is_pci = 0;
201 						break;
202 				case 'P':	is_pci = 1;
203 #ifdef CONFIG_BLK_DEV_IDEPCI
204 						if (hwif->pci_dev && !hwif->pci_dev->vendor)
205 							break;
206 #endif	/* CONFIG_BLK_DEV_IDEPCI */
207 						msg = "not a PCI device";
208 						goto parse_error;
209 				default:	msg = "expected 'R' or 'P'";
210 						goto parse_error;
211 			}
212 			digits = 0;
213 			while (n > 0 && (d = ide_getxdigit(*p)) >= 0) {
214 				reg = (reg << 4) | d;
215 				--n;
216 				++p;
217 				++digits;
218 			}
219 			if (!digits || (digits > 4) || (is_pci && reg > 0xff)) {
220 				msg = "bad/missing register number";
221 				goto parse_error;
222 			}
223 			if (n-- == 0 || *p++ != ':') {
224 				msg = "missing ':'";
225 				goto parse_error;
226 			}
227 			digits = 0;
228 			while (n > 0 && (d = ide_getxdigit(*p)) >= 0) {
229 				val = (val << 4) | d;
230 				--n;
231 				++p;
232 				++digits;
233 			}
234 			if (digits != 2 && digits != 4 && digits != 8) {
235 				msg = "bad data, 2/4/8 digits required";
236 				goto parse_error;
237 			}
238 			if (n > 0 && !isspace(*p)) {
239 				msg = "expected whitespace after data";
240 				goto parse_error;
241 			}
242 			while (n > 0 && isspace(*p)) {
243 				--n;
244 				++p;
245 			}
246 #ifdef CONFIG_BLK_DEV_IDEPCI
247 			if (is_pci && (reg & ((digits >> 1) - 1))) {
248 				msg = "misaligned access";
249 				goto parse_error;
250 			}
251 #endif	/* CONFIG_BLK_DEV_IDEPCI */
252 			if (for_real) {
253 #if 0
254 				printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? "PCI" : "non-PCI", reg, val, digits);
255 #endif
256 				if (is_pci) {
257 #ifdef CONFIG_BLK_DEV_IDEPCI
258 					int rc = 0;
259 					struct pci_dev *dev = hwif->pci_dev;
260 					switch (digits) {
261 						case 2:	msg = "byte";
262 							rc = pci_write_config_byte(dev, reg, val);
263 							break;
264 						case 4:	msg = "word";
265 							rc = pci_write_config_word(dev, reg, val);
266 							break;
267 						case 8:	msg = "dword";
268 							rc = pci_write_config_dword(dev, reg, val);
269 							break;
270 					}
271 					if (rc) {
272 #ifndef __PROC_HELL
273 						restore_flags(flags);	/* all CPUs */
274 #else
275 						spin_unlock_irqrestore(&io_request_lock, flags);
276 #endif
277 						printk("proc_ide_write_config: error writing %s at bus %02x dev %02x reg 0x%x value 0x%x\n",
278 							msg, dev->bus->number, dev->devfn, reg, val);
279 						printk("proc_ide_write_config: error %d\n", rc);
280 						return -EIO;
281 					}
282 #endif	/* CONFIG_BLK_DEV_IDEPCI */
283 				} else {	/* not pci */
284 #if !defined(__mc68000__) && !defined(CONFIG_APUS)
285 
286 /*
287  * Geert Uytterhoeven
288  *
289  * unless you can explain me what it really does.
290  * On m68k, we don't have outw() and outl() yet,
291  * and I need a good reason to implement it.
292  *
293  * BTW, IMHO the main remaining portability problem with the IDE driver
294  * is that it mixes IO (ioport) and MMIO (iomem) access on different platforms.
295  *
296  * I think all accesses should be done using
297  *
298  *     ide_in[bwl](ide_device_instance, offset)
299  *     ide_out[bwl](ide_device_instance, value, offset)
300  *
301  * so the architecture specific code can #define ide_{in,out}[bwl] to the
302  * appropriate function.
303  *
304  */
305 					switch (digits) {
306 						case 2:	hwif->OUTB(val, reg);
307 							break;
308 						case 4:	hwif->OUTW(val, reg);
309 							break;
310 						case 8:	hwif->OUTL(val, reg);
311 							break;
312 					}
313 #endif /* !__mc68000__ && !CONFIG_APUS */
314 				}
315 			}
316 		}
317 	} while (!for_real++);
318 #ifndef __PROC_HELL
319 	restore_flags(flags);	/* all CPUs */
320 #else
321 	spin_unlock_irqrestore(&io_request_lock, flags);
322 #endif
323 	return count;
324 parse_error:
325 #ifndef __PROC_HELL
326 	restore_flags(flags);	/* all CPUs */
327 #else
328 	spin_unlock_irqrestore(&io_request_lock, flags);
329 #endif
330 	printk("parse error\n");
331 	return xx_xx_parse_error(start, startn, msg);
332 }
333 
proc_ide_read_config(char * page,char ** start,off_t off,int count,int * eof,void * data)334 int proc_ide_read_config
335 	(char *page, char **start, off_t off, int count, int *eof, void *data)
336 {
337 	char		*out = page;
338 	int		len;
339 
340 #ifdef CONFIG_BLK_DEV_IDEPCI
341 	ide_hwif_t	*hwif = (ide_hwif_t *)data;
342 	struct pci_dev	*dev = hwif->pci_dev;
343 	if ((hwif->pci_dev && hwif->pci_dev->vendor) && dev && dev->bus) {
344 		int reg = 0;
345 
346 		out += sprintf(out, "pci bus %02x device %02x vendor %04x "
347 				"device %04x channel %d\n",
348 			dev->bus->number, dev->devfn,
349 			hwif->pci_dev->vendor, hwif->pci_dev->device,
350 			hwif->channel);
351 		do {
352 			u8 val;
353 			int rc = pci_read_config_byte(dev, reg, &val);
354 			if (rc) {
355 				printk("proc_ide_read_config: error %d reading"
356 					" bus %02x dev %02x reg 0x%02x\n",
357 					rc, dev->bus->number, dev->devfn, reg);
358 				out += sprintf(out, "??%c",
359 					(++reg & 0xf) ? ' ' : '\n');
360 			} else
361 				out += sprintf(out, "%02x%c",
362 					val, (++reg & 0xf) ? ' ' : '\n');
363 		} while (reg < 0x100);
364 	} else
365 #endif	/* CONFIG_BLK_DEV_IDEPCI */
366 		out += sprintf(out, "(none)\n");
367 	len = out - page;
368 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
369 }
370 
371 EXPORT_SYMBOL(proc_ide_read_config);
372 
ide_getdigit(char c)373 static int ide_getdigit(char c)
374 {
375 	int digit;
376 	if (isdigit(c))
377 		digit = c - '0';
378 	else
379 		digit = -1;
380 	return digit;
381 }
382 
proc_ide_read_drivers(char * page,char ** start,off_t off,int count,int * eof,void * data)383 int proc_ide_read_drivers
384 	(char *page, char **start, off_t off, int count, int *eof, void *data)
385 {
386 	char		*out = page;
387 	int		len;
388 	ide_module_t	*p = ide_modules;
389 	ide_driver_t	*driver;
390 
391 	while (p) {
392 		driver = (ide_driver_t *) p->info;
393 		if (driver)
394 			out += sprintf(out, "%s version %s\n",
395 				driver->name, driver->version);
396 		p = p->next;
397 	}
398 	len = out - page;
399 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
400 }
401 
402 EXPORT_SYMBOL(proc_ide_read_drivers);
403 
proc_ide_read_imodel(char * page,char ** start,off_t off,int count,int * eof,void * data)404 int proc_ide_read_imodel
405 	(char *page, char **start, off_t off, int count, int *eof, void *data)
406 {
407 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
408 	int		len;
409 	const char	*name;
410 
411 	switch (hwif->chipset) {
412 		case ide_unknown:	name = "(none)";	break;
413 		case ide_generic:	name = "generic";	break;
414 		case ide_pci:		name = "pci";		break;
415 		case ide_cmd640:	name = "cmd640";	break;
416 		case ide_dtc2278:	name = "dtc2278";	break;
417 		case ide_ali14xx:	name = "ali14xx";	break;
418 		case ide_qd65xx:	name = "qd65xx";	break;
419 		case ide_umc8672:	name = "umc8672";	break;
420 		case ide_ht6560b:	name = "ht6560b";	break;
421 		case ide_pdc4030:	name = "pdc4030";	break;
422 		case ide_rz1000:	name = "rz1000";	break;
423 		case ide_trm290:	name = "trm290";	break;
424 		case ide_cmd646:	name = "cmd646";	break;
425 		case ide_cy82c693:	name = "cy82c693";	break;
426 		case ide_4drives:	name = "4drives";	break;
427 		case ide_pmac:		name = "pmac";		break;
428 		default:		name = "(unknown)";	break;
429 	}
430 	len = sprintf(page, "%s\n", name);
431 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
432 }
433 
434 #ifdef CONFIG_ALL_PPC
proc_ide_read_devspec(char * page,char ** start,off_t off,int count,int * eof,void * data)435 static int proc_ide_read_devspec
436 	(char *page, char **start, off_t off, int count, int *eof, void *data)
437 {
438 	ide_hwif_t		*hwif = (ide_hwif_t *) data;
439 	int			len;
440 	struct device_node	*ofnode = NULL;
441 
442 #ifdef CONFIG_BLK_DEV_IDE_PMAC
443 	extern struct device_node* pmac_ide_get_of_node(int index);
444 	if (hwif->chipset == ide_pmac)
445 		ofnode = pmac_ide_get_of_node(hwif->index);
446 #endif /* CONFIG_BLK_DEV_IDE_PMAC */
447 #ifdef CONFIG_PCI
448 	if (ofnode == NULL && hwif->pci_dev)
449 		ofnode = pci_device_to_OF_node(hwif->pci_dev);
450 #endif /* CONFIG_PCI */
451 	len = sprintf(page, "%s\n", ofnode ? ofnode->full_name : "");
452 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
453 }
454 #endif /* CONFIG_ALL_PPC */
455 
456 EXPORT_SYMBOL(proc_ide_read_imodel);
457 
proc_ide_read_mate(char * page,char ** start,off_t off,int count,int * eof,void * data)458 int proc_ide_read_mate
459 	(char *page, char **start, off_t off, int count, int *eof, void *data)
460 {
461 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
462 	int		len;
463 
464 	if (hwif && hwif->mate && hwif->mate->present)
465 		len = sprintf(page, "%s\n", hwif->mate->name);
466 	else
467 		len = sprintf(page, "(none)\n");
468 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
469 }
470 
471 EXPORT_SYMBOL(proc_ide_read_mate);
472 
proc_ide_read_channel(char * page,char ** start,off_t off,int count,int * eof,void * data)473 int proc_ide_read_channel
474 	(char *page, char **start, off_t off, int count, int *eof, void *data)
475 {
476 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
477 	int		len;
478 
479 	page[0] = hwif->channel ? '1' : '0';
480 	page[1] = '\n';
481 	len = 2;
482 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
483 }
484 
485 EXPORT_SYMBOL(proc_ide_read_channel);
486 
proc_ide_read_identify(char * page,char ** start,off_t off,int count,int * eof,void * data)487 int proc_ide_read_identify
488 	(char *page, char **start, off_t off, int count, int *eof, void *data)
489 {
490 	ide_drive_t	*drive = (ide_drive_t *)data;
491 	int		len = 0, i = 0;
492 	int		err = 0;
493 
494 	len = sprintf(page, "\n");
495 
496 	if (drive)
497 	{
498 		unsigned short *val = (unsigned short *) page;
499 
500 		/*
501 		 *	The current code can't handle a driverless
502 		 *	identify query taskfile. Now the right fix is
503 		 *	to add a 'default' driver but that is a bit
504 		 *	more work.
505 		 *
506 		 *	FIXME: this has to be fixed for hotswap devices
507 		 */
508 
509 		if(DRIVER(drive))
510 			err = taskfile_lib_get_identify(drive, page);
511 		else	/* This relies on the ID changes */
512 			val = (unsigned short *)drive->id;
513 
514 		if(!err)
515 		{
516 			char *out = ((char *)page) + (SECTOR_WORDS * 4);
517 			page = out;
518 			do {
519 				out += sprintf(out, "%04x%c",
520 					le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
521 				val += 1;
522 			} while (i < (SECTOR_WORDS * 2));
523 			len = out - page;
524 		}
525 	}
526 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
527 }
528 
529 EXPORT_SYMBOL(proc_ide_read_identify);
530 
proc_ide_read_settings(char * page,char ** start,off_t off,int count,int * eof,void * data)531 int proc_ide_read_settings
532 	(char *page, char **start, off_t off, int count, int *eof, void *data)
533 {
534 	ide_drive_t	*drive = (ide_drive_t *) data;
535 	ide_settings_t	*setting = (ide_settings_t *) drive->settings;
536 	char		*out = page;
537 	int		len, rc, mul_factor, div_factor;
538 
539 	down(&ide_setting_sem);
540 	out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
541 	out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
542 	while(setting) {
543 		mul_factor = setting->mul_factor;
544 		div_factor = setting->div_factor;
545 		out += sprintf(out, "%-24s", setting->name);
546 		if ((rc = ide_read_setting(drive, setting)) >= 0)
547 			out += sprintf(out, "%-16d", rc * mul_factor / div_factor);
548 		else
549 			out += sprintf(out, "%-16s", "write-only");
550 		out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor);
551 		if (setting->rw & SETTING_READ)
552 			out += sprintf(out, "r");
553 		if (setting->rw & SETTING_WRITE)
554 			out += sprintf(out, "w");
555 		out += sprintf(out, "\n");
556 		setting = setting->next;
557 	}
558 	len = out - page;
559 	up(&ide_setting_sem);
560 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
561 }
562 
563 EXPORT_SYMBOL(proc_ide_read_settings);
564 
565 #define MAX_LEN	30
566 
proc_ide_write_settings(struct file * file,const char * buffer,unsigned long count,void * data)567 int proc_ide_write_settings
568 	(struct file *file, const char *buffer, unsigned long count, void *data)
569 {
570 	ide_drive_t	*drive = (ide_drive_t *) data;
571 	char		name[MAX_LEN + 1];
572 	int		for_real = 0, len;
573 	unsigned long	n;
574 	const char	*start = NULL;
575 	ide_settings_t	*setting;
576 
577 	if (!capable(CAP_SYS_ADMIN))
578 		return -EACCES;
579 	/*
580 	 * Skip over leading whitespace
581 	 */
582 	while (count && isspace(*buffer)) {
583 		--count;
584 		++buffer;
585 	}
586 	/*
587 	 * Do one full pass to verify all parameters,
588 	 * then do another to actually write the new settings.
589 	 */
590 	do {
591 		const char *p;
592 		p = buffer;
593 		n = count;
594 		while (n > 0) {
595 			int d, digits;
596 			unsigned int val = 0;
597 			start = p;
598 
599 			while (n > 0 && *p != ':') {
600 				--n;
601 				p++;
602 			}
603 			if (*p != ':')
604 				goto parse_error;
605 			len = IDE_MIN(p - start, MAX_LEN);
606 			strncpy(name, start, IDE_MIN(len, MAX_LEN));
607 			name[len] = 0;
608 
609 			if (n > 0) {
610 				--n;
611 				p++;
612 			} else
613 				goto parse_error;
614 
615 			digits = 0;
616 			while (n > 0 && (d = ide_getdigit(*p)) >= 0) {
617 				val = (val * 10) + d;
618 				--n;
619 				++p;
620 				++digits;
621 			}
622 			if (n > 0 && !isspace(*p))
623 				goto parse_error;
624 			while (n > 0 && isspace(*p)) {
625 				--n;
626 				++p;
627 			}
628 
629 			down(&ide_setting_sem);
630 			setting = ide_find_setting_by_name(drive, name);
631 			if (!setting)
632 			{
633 				up(&ide_setting_sem);
634 				goto parse_error;
635 			}
636 			if (for_real)
637 				ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor);
638 			up(&ide_setting_sem);
639 		}
640 	} while (!for_real++);
641 	return count;
642 parse_error:
643 	printk("proc_ide_write_settings(): parse error\n");
644 	return -EINVAL;
645 }
646 
647 EXPORT_SYMBOL(proc_ide_write_settings);
648 
proc_ide_read_capacity(char * page,char ** start,off_t off,int count,int * eof,void * data)649 int proc_ide_read_capacity
650 	(char *page, char **start, off_t off, int count, int *eof, void *data)
651 {
652 	ide_drive_t	*drive = (ide_drive_t *) data;
653 	int		len;
654 
655 	len = sprintf(page,"%llu\n",
656 		      (u64) ((ide_driver_t *)drive->driver)->capacity(drive));
657 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
658 }
659 
660 EXPORT_SYMBOL(proc_ide_read_capacity);
661 
proc_ide_read_geometry(char * page,char ** start,off_t off,int count,int * eof,void * data)662 int proc_ide_read_geometry
663 	(char *page, char **start, off_t off, int count, int *eof, void *data)
664 {
665 	ide_drive_t	*drive = (ide_drive_t *) data;
666 	char		*out = page;
667 	int		len;
668 
669 	out += sprintf(out,"physical     %d/%d/%d\n",
670 			drive->cyl, drive->head, drive->sect);
671 	out += sprintf(out,"logical      %d/%d/%d\n",
672 			drive->bios_cyl, drive->bios_head, drive->bios_sect);
673 
674 	len = out - page;
675 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
676 }
677 
678 EXPORT_SYMBOL(proc_ide_read_geometry);
679 
proc_ide_read_dmodel(char * page,char ** start,off_t off,int count,int * eof,void * data)680 int proc_ide_read_dmodel
681 	(char *page, char **start, off_t off, int count, int *eof, void *data)
682 {
683 	ide_drive_t	*drive = (ide_drive_t *) data;
684 	struct hd_driveid *id = drive->id;
685 	int		len;
686 
687 	len = sprintf(page, "%.40s\n",
688 		(id && id->model[0]) ? (char *)id->model : "(none)");
689 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
690 }
691 
692 EXPORT_SYMBOL(proc_ide_read_dmodel);
693 
proc_ide_read_driver(char * page,char ** start,off_t off,int count,int * eof,void * data)694 int proc_ide_read_driver
695 	(char *page, char **start, off_t off, int count, int *eof, void *data)
696 {
697 	ide_drive_t	*drive = (ide_drive_t *) data;
698 	ide_driver_t	*driver = (ide_driver_t *) drive->driver;
699 	int		len;
700 
701 	len = sprintf(page, "%s version %s\n",
702 		driver->name, driver->version);
703 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
704 }
705 
706 EXPORT_SYMBOL(proc_ide_read_driver);
707 
proc_ide_write_driver(struct file * file,const char * buffer,unsigned long count,void * data)708 int proc_ide_write_driver
709 	(struct file *file, const char *buffer, unsigned long count, void *data)
710 {
711 	ide_drive_t	*drive = (ide_drive_t *) data;
712 
713 	if (!capable(CAP_SYS_ADMIN))
714 		return -EACCES;
715 	if (ide_replace_subdriver(drive, buffer))
716 		return -EINVAL;
717 	return count;
718 }
719 
720 EXPORT_SYMBOL(proc_ide_write_driver);
721 
proc_ide_read_media(char * page,char ** start,off_t off,int count,int * eof,void * data)722 int proc_ide_read_media
723 	(char *page, char **start, off_t off, int count, int *eof, void *data)
724 {
725 	ide_drive_t	*drive = (ide_drive_t *) data;
726 	const char	*media;
727 	int		len;
728 
729 	switch (drive->media) {
730 		case ide_disk:	media = "disk\n";
731 				break;
732 		case ide_cdrom:	media = "cdrom\n";
733 				break;
734 		case ide_tape:	media = "tape\n";
735 				break;
736 		case ide_floppy:media = "floppy\n";
737 				break;
738 		default:	media = "UNKNOWN\n";
739 				break;
740 	}
741 	strcpy(page,media);
742 	len = strlen(media);
743 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
744 }
745 
746 EXPORT_SYMBOL(proc_ide_read_media);
747 
748 static ide_proc_entry_t generic_drive_entries[] = {
749 	{ "driver",	S_IFREG|S_IRUGO,	proc_ide_read_driver,	proc_ide_write_driver },
750 	{ "identify",	S_IFREG|S_IRUSR,	proc_ide_read_identify,	NULL },
751 	{ "media",	S_IFREG|S_IRUGO,	proc_ide_read_media,	NULL },
752 	{ "model",	S_IFREG|S_IRUGO,	proc_ide_read_dmodel,	NULL },
753 	{ "settings",	S_IFREG|S_IRUSR|S_IWUSR,proc_ide_read_settings,	proc_ide_write_settings },
754 	{ NULL,	0, NULL, NULL }
755 };
756 
ide_add_proc_entries(struct proc_dir_entry * dir,ide_proc_entry_t * p,void * data)757 void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
758 {
759 	struct proc_dir_entry *ent;
760 
761 	if (!dir || !p)
762 		return;
763 	while (p->name != NULL) {
764 		ent = create_proc_entry(p->name, p->mode, dir);
765 		if (!ent) return;
766 		ent->nlink = 1;
767 		ent->data = data;
768 		ent->read_proc = p->read_proc;
769 		ent->write_proc = p->write_proc;
770 		p++;
771 	}
772 }
773 
774 EXPORT_SYMBOL(ide_add_proc_entries);
775 
ide_remove_proc_entries(struct proc_dir_entry * dir,ide_proc_entry_t * p)776 void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
777 {
778 	if (!dir || !p)
779 		return;
780 	while (p->name != NULL) {
781 		remove_proc_entry(p->name, dir);
782 		p++;
783 	}
784 }
785 
786 EXPORT_SYMBOL(ide_remove_proc_entries);
787 
create_proc_ide_drives(ide_hwif_t * hwif)788 void create_proc_ide_drives(ide_hwif_t *hwif)
789 {
790 	int	d;
791 	struct proc_dir_entry *ent;
792 	struct proc_dir_entry *parent = hwif->proc;
793 	char name[64];
794 
795 	for (d = 0; d < MAX_DRIVES; d++) {
796 		ide_drive_t *drive = &hwif->drives[d];
797 
798 		if (!drive->present)
799 			continue;
800 		if (drive->proc)
801 			continue;
802 
803 		drive->proc = proc_mkdir(drive->name, parent);
804 		if (drive->proc)
805 			ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
806 		sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name);
807 		ent = proc_symlink(drive->name, proc_ide_root, name);
808 		if (!ent) return;
809 	}
810 }
811 
812 EXPORT_SYMBOL(create_proc_ide_drives);
813 
destroy_proc_ide_device(ide_hwif_t * hwif,ide_drive_t * drive)814 void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
815 {
816 	ide_driver_t *driver = drive->driver;
817 
818 	if (drive->proc) {
819 		ide_remove_proc_entries(drive->proc, driver->proc);
820 		ide_remove_proc_entries(drive->proc, generic_drive_entries);
821 		remove_proc_entry(drive->name, proc_ide_root);
822 		remove_proc_entry(drive->name, hwif->proc);
823 		drive->proc = NULL;
824 	}
825 }
826 
827 EXPORT_SYMBOL(destroy_proc_ide_device);
828 
destroy_proc_ide_drives(ide_hwif_t * hwif)829 void destroy_proc_ide_drives(ide_hwif_t *hwif)
830 {
831 	int	d;
832 
833 	for (d = 0; d < MAX_DRIVES; d++) {
834 		ide_drive_t *drive = &hwif->drives[d];
835 		if (drive->proc)
836 			destroy_proc_ide_device(hwif, drive);
837 	}
838 }
839 
840 EXPORT_SYMBOL(destroy_proc_ide_drives);
841 
842 static ide_proc_entry_t hwif_entries[] = {
843 	{ "channel",	S_IFREG|S_IRUGO,	proc_ide_read_channel,	NULL },
844 	{ "config",	S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config,	proc_ide_write_config },
845 	{ "mate",	S_IFREG|S_IRUGO,	proc_ide_read_mate,	NULL },
846 	{ "model",	S_IFREG|S_IRUGO,	proc_ide_read_imodel,	NULL },
847 #ifdef CONFIG_ALL_PPC
848 	{ "devspec",	S_IFREG|S_IRUGO,	proc_ide_read_devspec,	NULL },
849 #endif
850 	{ NULL,	0, NULL, NULL }
851 };
852 
create_proc_ide_interfaces(void)853 void create_proc_ide_interfaces(void)
854 {
855 	int	h;
856 
857 	for (h = 0; h < MAX_HWIFS; h++) {
858 		ide_hwif_t *hwif = &ide_hwifs[h];
859 
860 		if (!hwif->present)
861 			continue;
862 		if (!hwif->proc) {
863 			hwif->proc = proc_mkdir(hwif->name, proc_ide_root);
864 			if (!hwif->proc)
865 				return;
866 			ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
867 		}
868 		create_proc_ide_drives(hwif);
869 	}
870 }
871 
872 EXPORT_SYMBOL(create_proc_ide_interfaces);
873 
destroy_proc_ide_interfaces(void)874 void destroy_proc_ide_interfaces(void)
875 {
876 	int	h;
877 
878 	for (h = 0; h < MAX_HWIFS; h++) {
879 		ide_hwif_t *hwif = &ide_hwifs[h];
880 		int exist = (hwif->proc != NULL);
881 #if 0
882 		if (!hwif->present)
883 			continue;
884 #endif
885 		if (exist) {
886 			destroy_proc_ide_drives(hwif);
887 			ide_remove_proc_entries(hwif->proc, hwif_entries);
888 			remove_proc_entry(hwif->name, proc_ide_root);
889 			hwif->proc = NULL;
890 		} else
891 			continue;
892 	}
893 }
894 
895 EXPORT_SYMBOL(destroy_proc_ide_interfaces);
896 
897 #ifdef CONFIG_BLK_DEV_IDEPCI
ide_pci_register_host_proc(ide_pci_host_proc_t * p)898 void ide_pci_register_host_proc (ide_pci_host_proc_t *p)
899 {
900 	ide_pci_host_proc_t *tmp;
901 
902 	if (!p) return;
903 	p->next = NULL;
904 	p->set = 1;
905 	if (ide_pci_host_proc_list) {
906 		tmp = ide_pci_host_proc_list;
907 		while (tmp->next) tmp = tmp->next;
908 		tmp->next = p;
909 	} else
910 		ide_pci_host_proc_list = p;
911 }
912 
913 EXPORT_SYMBOL(ide_pci_register_host_proc);
914 
915 #endif /* CONFIG_BLK_DEV_IDEPCI */
916 
proc_ide_create(void)917 void proc_ide_create(void)
918 {
919 #ifdef CONFIG_BLK_DEV_IDEPCI
920 	ide_pci_host_proc_t *p = ide_pci_host_proc_list;
921 #endif /* CONFIG_BLK_DEV_IDEPCI */
922 
923 	proc_ide_root = proc_mkdir("ide", 0);
924 	if (!proc_ide_root) return;
925 
926 	create_proc_ide_interfaces();
927 
928 	create_proc_read_entry("drivers", 0, proc_ide_root,
929 				proc_ide_read_drivers, NULL);
930 
931 #ifdef CONFIG_BLK_DEV_IDEPCI
932 	while (p != NULL)
933 	{
934 		if (p->name != NULL && p->set == 1 && p->get_info != NULL)
935 		{
936 			p->parent = proc_ide_root;
937 			create_proc_info_entry(p->name, 0, p->parent, p->get_info);
938 			p->set = 2;
939 		}
940 		p = p->next;
941 	}
942 #endif /* CONFIG_BLK_DEV_IDEPCI */
943 }
944 
945 EXPORT_SYMBOL(proc_ide_create);
946 
proc_ide_destroy(void)947 void proc_ide_destroy(void)
948 {
949 #ifdef CONFIG_BLK_DEV_IDEPCI
950 	ide_pci_host_proc_t *p;
951 
952 	for (p = ide_pci_host_proc_list; p; p = p->next) {
953 		if (p->set == 2)
954 			remove_proc_entry(p->name, p->parent);
955 	}
956 #endif /* CONFIG_BLK_DEV_IDEPCI */
957 	remove_proc_entry("ide/drivers", proc_ide_root);
958 	destroy_proc_ide_interfaces();
959 	remove_proc_entry("ide", 0);
960 }
961 
962 EXPORT_SYMBOL(proc_ide_destroy);
963