aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ide/ide-proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ide/ide-proc.c')
-rw-r--r--drivers/ide/ide-proc.c306
1 files changed, 93 insertions, 213 deletions
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index f66c9c3f6fc6..e7030a491463 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -12,14 +12,6 @@
12 * "settings" files. e.g. "cat /proc/ide0/hda/settings" 12 * "settings" files. e.g. "cat /proc/ide0/hda/settings"
13 * To write a new value "val" into a specific setting "name", use: 13 * To write a new value "val" into a specific setting "name", use:
14 * echo "name:val" >/proc/ide/ide0/hda/settings 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 */ 15 */
24 16
25#include <linux/module.h> 17#include <linux/module.h>
@@ -31,7 +23,6 @@
31#include <linux/mm.h> 23#include <linux/mm.h>
32#include <linux/pci.h> 24#include <linux/pci.h>
33#include <linux/ctype.h> 25#include <linux/ctype.h>
34#include <linux/hdreg.h>
35#include <linux/ide.h> 26#include <linux/ide.h>
36#include <linux/seq_file.h> 27#include <linux/seq_file.h>
37 28
@@ -109,13 +100,14 @@ static int proc_ide_read_identify
109 100
110 err = taskfile_lib_get_identify(drive, page); 101 err = taskfile_lib_get_identify(drive, page);
111 if (!err) { 102 if (!err) {
112 char *out = ((char *)page) + (SECTOR_WORDS * 4); 103 char *out = (char *)page + SECTOR_SIZE;
104
113 page = out; 105 page = out;
114 do { 106 do {
115 out += sprintf(out, "%04x%c", 107 out += sprintf(out, "%04x%c",
116 le16_to_cpup(val), (++i & 7) ? ' ' : '\n'); 108 le16_to_cpup(val), (++i & 7) ? ' ' : '\n');
117 val += 1; 109 val += 1;
118 } while (i < (SECTOR_WORDS * 2)); 110 } while (i < SECTOR_SIZE / 2);
119 len = out - page; 111 len = out - page;
120 } 112 }
121 } 113 }
@@ -123,140 +115,25 @@ static int proc_ide_read_identify
123} 115}
124 116
125/** 117/**
126 * __ide_add_setting - add an ide setting option 118 * ide_find_setting - find a specific setting
127 * @drive: drive to use 119 * @st: setting table pointer
128 * @name: setting name
129 * @rw: true if the function is read write
130 * @data_type: type of data
131 * @min: range minimum
132 * @max: range maximum
133 * @mul_factor: multiplication scale
134 * @div_factor: divison scale
135 * @data: private data field
136 * @set: setting
137 * @auto_remove: setting auto removal flag
138 *
139 * Removes the setting named from the device if it is present.
140 * The function takes the settings_lock to protect against
141 * parallel changes. This function must not be called from IRQ
142 * context. Returns 0 on success or -1 on failure.
143 *
144 * BUGS: This code is seriously over-engineered. There is also
145 * magic about how the driver specific features are setup. If
146 * a driver is attached we assume the driver settings are auto
147 * remove.
148 */
149
150static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove)
151{
152 ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
153
154 mutex_lock(&ide_setting_mtx);
155 while ((*p) && strcmp((*p)->name, name) < 0)
156 p = &((*p)->next);
157 if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
158 goto abort;
159 if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
160 goto abort;
161 strcpy(setting->name, name);
162 setting->rw = rw;
163 setting->data_type = data_type;
164 setting->min = min;
165 setting->max = max;
166 setting->mul_factor = mul_factor;
167 setting->div_factor = div_factor;
168 setting->data = data;
169 setting->set = set;
170
171 setting->next = *p;
172 if (auto_remove)
173 setting->auto_remove = 1;
174 *p = setting;
175 mutex_unlock(&ide_setting_mtx);
176 return 0;
177abort:
178 mutex_unlock(&ide_setting_mtx);
179 kfree(setting);
180 return -1;
181}
182
183int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
184{
185 return __ide_add_setting(drive, name, rw, data_type, min, max, mul_factor, div_factor, data, set, 1);
186}
187
188EXPORT_SYMBOL(ide_add_setting);
189
190/**
191 * __ide_remove_setting - remove an ide setting option
192 * @drive: drive to use
193 * @name: setting name
194 *
195 * Removes the setting named from the device if it is present.
196 * The caller must hold the setting semaphore.
197 */
198
199static void __ide_remove_setting(ide_drive_t *drive, char *name)
200{
201 ide_settings_t **p, *setting;
202
203 p = (ide_settings_t **) &drive->settings;
204
205 while ((*p) && strcmp((*p)->name, name))
206 p = &((*p)->next);
207 setting = (*p);
208 if (setting == NULL)
209 return;
210
211 (*p) = setting->next;
212
213 kfree(setting->name);
214 kfree(setting);
215}
216
217/**
218 * auto_remove_settings - remove driver specific settings
219 * @drive: drive
220 *
221 * Automatically remove all the driver specific settings for this
222 * drive. This function may not be called from IRQ context. The
223 * caller must hold ide_setting_mtx.
224 */
225
226static void auto_remove_settings(ide_drive_t *drive)
227{
228 ide_settings_t *setting;
229repeat:
230 setting = drive->settings;
231 while (setting) {
232 if (setting->auto_remove) {
233 __ide_remove_setting(drive, setting->name);
234 goto repeat;
235 }
236 setting = setting->next;
237 }
238}
239
240/**
241 * ide_find_setting_by_name - find a drive specific setting
242 * @drive: drive to scan
243 * @name: setting name 120 * @name: setting name
244 * 121 *
245 * Scan's the device setting table for a matching entry and returns 122 * Scan's the setting table for a matching entry and returns
246 * this or NULL if no entry is found. The caller must hold the 123 * this or NULL if no entry is found. The caller must hold the
247 * setting semaphore 124 * setting semaphore
248 */ 125 */
249 126
250static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name) 127static
128const struct ide_proc_devset *ide_find_setting(const struct ide_proc_devset *st,
129 char *name)
251{ 130{
252 ide_settings_t *setting = drive->settings; 131 while (st->name) {
253 132 if (strcmp(st->name, name) == 0)
254 while (setting) {
255 if (strcmp(setting->name, name) == 0)
256 break; 133 break;
257 setting = setting->next; 134 st++;
258 } 135 }
259 return setting; 136 return st->name ? st : NULL;
260} 137}
261 138
262/** 139/**
@@ -272,26 +149,20 @@ static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name)
272 * be told apart 149 * be told apart
273 */ 150 */
274 151
275static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting) 152static int ide_read_setting(ide_drive_t *drive,
153 const struct ide_proc_devset *setting)
276{ 154{
277 int val = -EINVAL; 155 const struct ide_devset *ds = setting->setting;
278 unsigned long flags; 156 int val = -EINVAL;
157
158 if (ds->get) {
159 unsigned long flags;
279 160
280 if ((setting->rw & SETTING_READ)) {
281 spin_lock_irqsave(&ide_lock, flags); 161 spin_lock_irqsave(&ide_lock, flags);
282 switch (setting->data_type) { 162 val = ds->get(drive);
283 case TYPE_BYTE:
284 val = *((u8 *) setting->data);
285 break;
286 case TYPE_SHORT:
287 val = *((u16 *) setting->data);
288 break;
289 case TYPE_INT:
290 val = *((u32 *) setting->data);
291 break;
292 }
293 spin_unlock_irqrestore(&ide_lock, flags); 163 spin_unlock_irqrestore(&ide_lock, flags);
294 } 164 }
165
295 return val; 166 return val;
296} 167}
297 168
@@ -313,33 +184,23 @@ static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting)
313 * The current scheme of polling is kludgy, though safe enough. 184 * The current scheme of polling is kludgy, though safe enough.
314 */ 185 */
315 186
316static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val) 187static int ide_write_setting(ide_drive_t *drive,
188 const struct ide_proc_devset *setting, int val)
317{ 189{
190 const struct ide_devset *ds = setting->setting;
191
318 if (!capable(CAP_SYS_ADMIN)) 192 if (!capable(CAP_SYS_ADMIN))
319 return -EACCES; 193 return -EACCES;
320 if (setting->set) 194 if (!ds->set)
321 return setting->set(drive, val);
322 if (!(setting->rw & SETTING_WRITE))
323 return -EPERM; 195 return -EPERM;
324 if (val < setting->min || val > setting->max) 196 if ((ds->flags & DS_SYNC)
197 && (val < setting->min || val > setting->max))
325 return -EINVAL; 198 return -EINVAL;
326 if (ide_spin_wait_hwgroup(drive)) 199 return ide_devset_execute(drive, ds, val);
327 return -EBUSY;
328 switch (setting->data_type) {
329 case TYPE_BYTE:
330 *((u8 *) setting->data) = val;
331 break;
332 case TYPE_SHORT:
333 *((u16 *) setting->data) = val;
334 break;
335 case TYPE_INT:
336 *((u32 *) setting->data) = val;
337 break;
338 }
339 spin_unlock_irq(&ide_lock);
340 return 0;
341} 200}
342 201
202ide_devset_get(xfer_rate, current_speed);
203
343static int set_xfer_rate (ide_drive_t *drive, int arg) 204static int set_xfer_rate (ide_drive_t *drive, int arg)
344{ 205{
345 ide_task_t task; 206 ide_task_t task;
@@ -349,7 +210,7 @@ static int set_xfer_rate (ide_drive_t *drive, int arg)
349 return -EINVAL; 210 return -EINVAL;
350 211
351 memset(&task, 0, sizeof(task)); 212 memset(&task, 0, sizeof(task));
352 task.tf.command = WIN_SETFEATURES; 213 task.tf.command = ATA_CMD_SET_FEATURES;
353 task.tf.feature = SETFEATURES_XFER; 214 task.tf.feature = SETFEATURES_XFER;
354 task.tf.nsect = (u8)arg; 215 task.tf.nsect = (u8)arg;
355 task.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT | 216 task.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT |
@@ -364,29 +225,23 @@ static int set_xfer_rate (ide_drive_t *drive, int arg)
364 return err; 225 return err;
365} 226}
366 227
367/** 228ide_devset_rw(current_speed, xfer_rate);
368 * ide_add_generic_settings - generic ide settings 229ide_devset_rw_field(init_speed, init_speed);
369 * @drive: drive being configured 230ide_devset_rw_field(nice1, nice1);
370 * 231ide_devset_rw_field(number, dn);
371 * Add the generic parts of the system settings to the /proc files. 232
372 * The caller must not be holding the ide_setting_mtx. 233static const struct ide_proc_devset ide_generic_settings[] = {
373 */ 234 IDE_PROC_DEVSET(current_speed, 0, 70),
374 235 IDE_PROC_DEVSET(init_speed, 0, 70),
375void ide_add_generic_settings (ide_drive_t *drive) 236 IDE_PROC_DEVSET(io_32bit, 0, 1 + (SUPPORT_VLB_SYNC << 1)),
376{ 237 IDE_PROC_DEVSET(keepsettings, 0, 1),
377/* 238 IDE_PROC_DEVSET(nice1, 0, 1),
378 * drive setting name read/write access data type min max mul_factor div_factor data pointer set function 239 IDE_PROC_DEVSET(number, 0, 3),
379 */ 240 IDE_PROC_DEVSET(pio_mode, 0, 255),
380 __ide_add_setting(drive, "io_32bit", drive->no_io_32bit ? SETTING_READ : SETTING_RW, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->io_32bit, set_io_32bit, 0); 241 IDE_PROC_DEVSET(unmaskirq, 0, 1),
381 __ide_add_setting(drive, "keepsettings", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, NULL, 0); 242 IDE_PROC_DEVSET(using_dma, 0, 1),
382 __ide_add_setting(drive, "nice1", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->nice1, NULL, 0); 243 { 0 },
383 __ide_add_setting(drive, "pio_mode", SETTING_WRITE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode, 0); 244};
384 __ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL, 0);
385 __ide_add_setting(drive, "using_dma", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma, 0);
386 __ide_add_setting(drive, "init_speed", SETTING_RW, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL, 0);
387 __ide_add_setting(drive, "current_speed", SETTING_RW, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate, 0);
388 __ide_add_setting(drive, "number", SETTING_RW, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL, 0);
389}
390 245
391static void proc_ide_settings_warn(void) 246static void proc_ide_settings_warn(void)
392{ 247{
@@ -403,19 +258,32 @@ static void proc_ide_settings_warn(void)
403static int proc_ide_read_settings 258static int proc_ide_read_settings
404 (char *page, char **start, off_t off, int count, int *eof, void *data) 259 (char *page, char **start, off_t off, int count, int *eof, void *data)
405{ 260{
261 const struct ide_proc_devset *setting, *g, *d;
262 const struct ide_devset *ds;
406 ide_drive_t *drive = (ide_drive_t *) data; 263 ide_drive_t *drive = (ide_drive_t *) data;
407 ide_settings_t *setting = (ide_settings_t *) drive->settings;
408 char *out = page; 264 char *out = page;
409 int len, rc, mul_factor, div_factor; 265 int len, rc, mul_factor, div_factor;
410 266
411 proc_ide_settings_warn(); 267 proc_ide_settings_warn();
412 268
413 mutex_lock(&ide_setting_mtx); 269 mutex_lock(&ide_setting_mtx);
270 g = ide_generic_settings;
271 d = drive->settings;
414 out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n"); 272 out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
415 out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n"); 273 out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
416 while (setting) { 274 while (g->name || (d && d->name)) {
417 mul_factor = setting->mul_factor; 275 /* read settings in the alphabetical order */
418 div_factor = setting->div_factor; 276 if (g->name && d && d->name) {
277 if (strcmp(d->name, g->name) < 0)
278 setting = d++;
279 else
280 setting = g++;
281 } else if (d && d->name) {
282 setting = d++;
283 } else
284 setting = g++;
285 mul_factor = setting->mulf ? setting->mulf(drive) : 1;
286 div_factor = setting->divf ? setting->divf(drive) : 1;
419 out += sprintf(out, "%-24s", setting->name); 287 out += sprintf(out, "%-24s", setting->name);
420 rc = ide_read_setting(drive, setting); 288 rc = ide_read_setting(drive, setting);
421 if (rc >= 0) 289 if (rc >= 0)
@@ -423,12 +291,12 @@ static int proc_ide_read_settings
423 else 291 else
424 out += sprintf(out, "%-16s", "write-only"); 292 out += sprintf(out, "%-16s", "write-only");
425 out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor); 293 out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor);
426 if (setting->rw & SETTING_READ) 294 ds = setting->setting;
295 if (ds->get)
427 out += sprintf(out, "r"); 296 out += sprintf(out, "r");
428 if (setting->rw & SETTING_WRITE) 297 if (ds->set)
429 out += sprintf(out, "w"); 298 out += sprintf(out, "w");
430 out += sprintf(out, "\n"); 299 out += sprintf(out, "\n");
431 setting = setting->next;
432 } 300 }
433 len = out - page; 301 len = out - page;
434 mutex_unlock(&ide_setting_mtx); 302 mutex_unlock(&ide_setting_mtx);
@@ -442,9 +310,10 @@ static int proc_ide_write_settings(struct file *file, const char __user *buffer,
442{ 310{
443 ide_drive_t *drive = (ide_drive_t *) data; 311 ide_drive_t *drive = (ide_drive_t *) data;
444 char name[MAX_LEN + 1]; 312 char name[MAX_LEN + 1];
445 int for_real = 0; 313 int for_real = 0, mul_factor, div_factor;
446 unsigned long n; 314 unsigned long n;
447 ide_settings_t *setting; 315
316 const struct ide_proc_devset *setting;
448 char *buf, *s; 317 char *buf, *s;
449 318
450 if (!capable(CAP_SYS_ADMIN)) 319 if (!capable(CAP_SYS_ADMIN))
@@ -512,13 +381,21 @@ static int proc_ide_write_settings(struct file *file, const char __user *buffer,
512 } 381 }
513 382
514 mutex_lock(&ide_setting_mtx); 383 mutex_lock(&ide_setting_mtx);
515 setting = ide_find_setting_by_name(drive, name); 384 /* generic settings first, then driver specific ones */
385 setting = ide_find_setting(ide_generic_settings, name);
516 if (!setting) { 386 if (!setting) {
517 mutex_unlock(&ide_setting_mtx); 387 if (drive->settings)
518 goto parse_error; 388 setting = ide_find_setting(drive->settings, name);
389 if (!setting) {
390 mutex_unlock(&ide_setting_mtx);
391 goto parse_error;
392 }
393 }
394 if (for_real) {
395 mul_factor = setting->mulf ? setting->mulf(drive) : 1;
396 div_factor = setting->divf ? setting->divf(drive) : 1;
397 ide_write_setting(drive, setting, val * div_factor / mul_factor);
519 } 398 }
520 if (for_real)
521 ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor);
522 mutex_unlock(&ide_setting_mtx); 399 mutex_unlock(&ide_setting_mtx);
523 } 400 }
524 } while (!for_real++); 401 } while (!for_real++);
@@ -561,11 +438,10 @@ static int proc_ide_read_dmodel
561 (char *page, char **start, off_t off, int count, int *eof, void *data) 438 (char *page, char **start, off_t off, int count, int *eof, void *data)
562{ 439{
563 ide_drive_t *drive = (ide_drive_t *) data; 440 ide_drive_t *drive = (ide_drive_t *) data;
564 struct hd_driveid *id = drive->id; 441 char *m = (char *)&drive->id[ATA_ID_PROD];
565 int len; 442 int len;
566 443
567 len = sprintf(page, "%.40s\n", 444 len = sprintf(page, "%.40s\n", m[0] ? m : "(none)");
568 (id && id->model[0]) ? (char *)id->model : "(none)");
569 PROC_IDE_READ_RETURN(page, start, off, count, eof, len); 445 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
570} 446}
571 447
@@ -690,6 +566,10 @@ static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t
690 566
691void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) 567void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver)
692{ 568{
569 mutex_lock(&ide_setting_mtx);
570 drive->settings = driver->settings;
571 mutex_unlock(&ide_setting_mtx);
572
693 ide_add_proc_entries(drive->proc, driver->proc, drive); 573 ide_add_proc_entries(drive->proc, driver->proc, drive);
694} 574}
695 575
@@ -726,7 +606,7 @@ void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver)
726 * OTOH both ide_{read,write}_setting are only ever used under 606 * OTOH both ide_{read,write}_setting are only ever used under
727 * ide_setting_mtx. 607 * ide_setting_mtx.
728 */ 608 */
729 auto_remove_settings(drive); 609 drive->settings = NULL;
730 spin_unlock_irqrestore(&ide_lock, flags); 610 spin_unlock_irqrestore(&ide_lock, flags);
731 mutex_unlock(&ide_setting_mtx); 611 mutex_unlock(&ide_setting_mtx);
732} 612}