summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/sd_ioctl.c
blob: 2f771552a17ca77dd7caef022461dec4aa13962f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * drivers/scsi/sd_ioctl.c
 *
 * ioctl handling for SCSI disks
 */

#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/hdreg.h>
#include <linux/errno.h>

#include <asm/uaccess.h>

#include <linux/blk.h>
#include "scsi.h"
#include <scsi/scsi_ioctl.h>
#include "hosts.h"
#include "sd.h"
#include <scsi/scsicam.h>     /* must follow "hosts.h" */

int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
{
    kdev_t dev = inode->i_rdev;
    int error;
    struct Scsi_Host * host;
    Scsi_Device * SDev;
    int diskinfo[4];
    struct hd_geometry *loc = (struct hd_geometry *) arg;
    
    SDev = rscsi_disks[MINOR(dev) >> 4].device;
    /*
     * If we are in the middle of error recovery, don't let anyone
     * else try and use this device.  Also, if error recovery fails, it
     * may try and take the device offline, in which case all further
     * access to the device is prohibited.
     */
    if( !scsi_block_when_processing_errors(SDev) )
      {
        return -ENODEV;
      }

    switch (cmd) {
    case HDIO_GETGEO:   /* Return BIOS disk parameters */
	if (!loc)  return -EINVAL;
	error = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
	if (error)
	    return error;
	host = rscsi_disks[MINOR(dev) >> 4].device->host;

/* default to most commonly used values */

        diskinfo[0] = 0x40;
        diskinfo[1] = 0x20;
        diskinfo[2] = rscsi_disks[MINOR(dev) >> 4].capacity >> 11;

/* override with calculated, extended default, or driver values */

	if(host->hostt->bios_param != NULL)
	    host->hostt->bios_param(&rscsi_disks[MINOR(dev) >> 4],
				    dev,
				    &diskinfo[0]);
        else scsicam_bios_param(&rscsi_disks[MINOR(dev) >> 4],
				dev, &diskinfo[0]);

	put_user(diskinfo[0], &loc->heads);
	put_user(diskinfo[1], &loc->sectors);
	put_user(diskinfo[2], &loc->cylinders);
	put_user(sd[MINOR(inode->i_rdev)].start_sect, &loc->start);
	return 0;
    case BLKGETSIZE:   /* Return device size */
	if (!arg)  return -EINVAL;
	error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
	if (error)
	    return error;
	put_user(sd[MINOR(inode->i_rdev)].nr_sects,
		 (long *) arg);
	return 0;

    case BLKRASET:
	if (!suser())
		return -EACCES;
	if(!(inode->i_rdev)) return -EINVAL;
	if(arg > 0xff) return -EINVAL;
	read_ahead[MAJOR(inode->i_rdev)] = arg;
	return 0;

    case BLKRAGET:
	if (!arg)
		return -EINVAL;
	error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
	if (error)
	    return error;
	put_user(read_ahead[MAJOR(inode->i_rdev)], (long *) arg);
	return 0;

    case BLKFLSBUF:
	if(!suser())  return -EACCES;
	if(!(inode->i_rdev)) return -EINVAL;
	fsync_dev(inode->i_rdev);
	invalidate_buffers(inode->i_rdev);
	return 0;
	
    case BLKRRPART: /* Re-read partition tables */
	return revalidate_scsidisk(dev, 1);

    RO_IOCTLS(dev, arg);

    default:
	return scsi_ioctl(rscsi_disks[MINOR(dev) >> 4].device , cmd, (void *) arg);
    }
}

/*
 * Overrides for Emacs so that we follow Linus's tabbing style.
 * Emacs will notice this stuff at the end of the file and automatically
 * adjust the settings for this buffer only.  This must remain at the end
 * of the file.
 * ---------------------------------------------------------------------------
 * Local variables:
 * c-indent-level: 4
 * c-brace-imaginary-offset: 0
 * c-brace-offset: -4
 * c-argdecl-indent: 4
 * c-label-offset: -4
 * c-continued-statement-offset: 4
 * c-continued-brace-offset: 0
 * indent-tabs-mode: nil
 * tab-width: 8
 * End:
 */