Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a885c8c4 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Linus Torvalds
Browse files

[PATCH] Add block_device_operations.getgeo block device method



HDIO_GETGEO is implemented in most block drivers, and all of them have to
duplicate the code to copy the structure to userspace, as well as getting
the start sector.  This patch moves that to common code [1] and adds a
->getgeo method to fill out the raw kernel hd_geometry structure.  For many
drivers this means ->ioctl can go away now.

[1] the s390 block drivers are odd in this respect.  xpram sets ->start
    to 4 always which seems more than odd, and the dasd driver shifts
    the start offset around, probably because of it's non-standard
    sector size.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Cc: Jens Axboe <axboe@suse.de>
Cc: <mike.miller@hp.com>
Cc: Jeff Dike <jdike@addtoit.com>
Cc: Paolo Giarrusso <blaisorblade@yahoo.it>
Cc: Bartlomiej Zolnierkiewicz <B.Zolnierkiewicz@elka.pw.edu.pl>
Cc: Neil Brown <neilb@cse.unsw.edu.au>
Cc: Markus Lidel <Markus.Lidel@shadowconnect.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Signed-off-by: default avatarAdrian Bunk <bunk@stusta.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 5b0ed2c6
Loading
Loading
Loading
Loading
+12 −9
Original line number Diff line number Diff line
@@ -117,6 +117,7 @@ static int ubd_open(struct inode * inode, struct file * filp);
static int ubd_release(struct inode * inode, struct file * file);
static int ubd_ioctl(struct inode * inode, struct file * file,
		     unsigned int cmd, unsigned long arg);
static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);

#define MAX_DEV (8)

@@ -125,6 +126,7 @@ static struct block_device_operations ubd_blops = {
        .open		= ubd_open,
        .release	= ubd_release,
        .ioctl		= ubd_ioctl,
	.getgeo		= ubd_getgeo,
};

/* Protected by the queue_lock */
@@ -1058,6 +1060,16 @@ static void do_ubd_request(request_queue_t *q)
	}
}

static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
	struct ubd *dev = bdev->bd_disk->private_data;

	geo->heads = 128;
	geo->sectors = 32;
	geo->cylinders = dev->size / (128 * 32 * 512);
	return 0;
}

static int ubd_ioctl(struct inode * inode, struct file * file,
		     unsigned int cmd, unsigned long arg)
{
@@ -1070,16 +1082,7 @@ static int ubd_ioctl(struct inode * inode, struct file * file,
	};

	switch (cmd) {
	        struct hd_geometry g;
		struct cdrom_volctrl volume;
	case HDIO_GETGEO:
		if(!loc) return(-EINVAL);
		g.heads = 128;
		g.sectors = 32;
		g.cylinders = dev->size / (128 * 32 * 512);
		g.start = get_start_sect(inode->i_bdev);
		return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0);

	case HDIO_GET_IDENTITY:
		ubd_id.cyls = dev->size / (128 * 32 * 512);
		if(copy_to_user((char __user *) arg, (char *) &ubd_id,
+22 −0
Original line number Diff line number Diff line
#include <linux/sched.h>		/* for capable() */
#include <linux/blkdev.h>
#include <linux/blkpg.h>
#include <linux/hdreg.h>
#include <linux/backing-dev.h>
#include <linux/buffer_head.h>
#include <linux/smp_lock.h>
@@ -245,6 +246,27 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
		set_device_ro(bdev, n);
		unlock_kernel();
		return 0;
	case HDIO_GETGEO: {
		struct hd_geometry geo;

		if (!arg)
			return -EINVAL;
		if (!disk->fops->getgeo)
			return -ENOTTY;

		/*
		 * We need to set the startsect first, the driver may
		 * want to override it.
		 */
		geo.start = get_start_sect(bdev);
		ret = disk->fops->getgeo(bdev, &geo);
		if (ret)
			return ret;
		if (copy_to_user((struct hd_geometry __user *)arg, &geo,
					sizeof(geo)))
			return -EFAULT;
		return 0;
	}
	}

	lock_kernel();
+7 −29
Original line number Diff line number Diff line
@@ -129,19 +129,6 @@ static DEFINE_SPINLOCK(mfm_lock);
#define MAJOR_NR	MFM_ACORN_MAJOR
#define QUEUE (mfm_queue)
#define CURRENT elv_next_request(mfm_queue)
/*
 * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc
 */
#ifndef HDIO_GETGEO
#define HDIO_GETGEO 0x301
struct hd_geometry {
	unsigned char heads;
	unsigned char sectors;
	unsigned short cylinders;
	unsigned long start;
};
#endif


/*
 * Configuration section
@@ -1153,22 +1140,13 @@ static int mfm_initdrives(void)
 * The 'front' end of the mfm driver follows...
 */

static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg)
static int mfm_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
	struct mfm_info *p = inode->i_bdev->bd_disk->private_data;
	struct hd_geometry *geo = (struct hd_geometry *) arg;
	if (cmd != HDIO_GETGEO)
		return -EINVAL;
	if (!arg)
		return -EINVAL;
	if (put_user (p->heads, &geo->heads))
		return -EFAULT;
	if (put_user (p->sectors, &geo->sectors))
		return -EFAULT;
	if (put_user (p->cylinders, &geo->cylinders))
		return -EFAULT;
	if (put_user (get_start_sect(inode->i_bdev), &geo->start))
		return -EFAULT;
	struct mfm_info *p = bdev->bd_disk->private_data;

	geo->heads = p->heads;
	geo->sectors = p->sectors;
	geo->cylinders = p->cylinders;
	return 0;
}

@@ -1219,7 +1197,7 @@ void xd_set_geometry(struct block_device *bdev, unsigned char secsptrack,
static struct block_device_operations mfm_fops =
{
	.owner		= THIS_MODULE,
	.ioctl		= mfm_ioctl,
	.getgeo		= mfm_getgeo,
};

/*
+14 −21
Original line number Diff line number Diff line
@@ -92,34 +92,28 @@ static int DAC960_open(struct inode *inode, struct file *file)
	return 0;
}

static int DAC960_ioctl(struct inode *inode, struct file *file,
			unsigned int cmd, unsigned long arg)
static int DAC960_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
	struct gendisk *disk = inode->i_bdev->bd_disk;
	struct gendisk *disk = bdev->bd_disk;
	DAC960_Controller_T *p = disk->queue->queuedata;
	int drive_nr = (long)disk->private_data;
	struct hd_geometry g;
	struct hd_geometry __user *loc = (struct hd_geometry __user *)arg;

	if (cmd != HDIO_GETGEO || !loc)
		return -EINVAL;

	if (p->FirmwareType == DAC960_V1_Controller) {
		g.heads = p->V1.GeometryTranslationHeads;
		g.sectors = p->V1.GeometryTranslationSectors;
		g.cylinders = p->V1.LogicalDriveInformation[drive_nr].
			LogicalDriveSize / (g.heads * g.sectors);
		geo->heads = p->V1.GeometryTranslationHeads;
		geo->sectors = p->V1.GeometryTranslationSectors;
		geo->cylinders = p->V1.LogicalDriveInformation[drive_nr].
			LogicalDriveSize / (geo->heads * geo->sectors);
	} else {
		DAC960_V2_LogicalDeviceInfo_T *i =
			p->V2.LogicalDeviceInformation[drive_nr];
		switch (i->DriveGeometry) {
		case DAC960_V2_Geometry_128_32:
			g.heads = 128;
			g.sectors = 32;
			geo->heads = 128;
			geo->sectors = 32;
			break;
		case DAC960_V2_Geometry_255_63:
			g.heads = 255;
			g.sectors = 63;
			geo->heads = 255;
			geo->sectors = 63;
			break;
		default:
			DAC960_Error("Illegal Logical Device Geometry %d\n",
@@ -127,12 +121,11 @@ static int DAC960_ioctl(struct inode *inode, struct file *file,
			return -EINVAL;
		}

		g.cylinders = i->ConfigurableDeviceSize / (g.heads * g.sectors);
		geo->cylinders = i->ConfigurableDeviceSize /
			(geo->heads * geo->sectors);
	}
	
	g.start = get_start_sect(inode->i_bdev);

	return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
	return 0;
}

static int DAC960_media_changed(struct gendisk *disk)
@@ -157,7 +150,7 @@ static int DAC960_revalidate_disk(struct gendisk *disk)
static struct block_device_operations DAC960_BlockDeviceOperations = {
	.owner			= THIS_MODULE,
	.open			= DAC960_open,
	.ioctl			= DAC960_ioctl,
	.getgeo			= DAC960_getgeo,
	.media_changed		= DAC960_media_changed,
	.revalidate_disk	= DAC960_revalidate_disk,
};
+14 −12
Original line number Diff line number Diff line
@@ -1079,6 +1079,19 @@ static void redo_acsi_request( void )
 *
 ***********************************************************************/

static int acsi_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
	struct acsi_info_struct *aip = bdev->bd_disk->private_data;

	/*
	 * Just fake some geometry here, it's nonsense anyway
	 * To make it easy, use Adaptec's usual 64/32 mapping
	 */
	geo->heads = 64;
	geo->sectors = 32;
	geo->cylinders = aip->size >> 11;
	return 0;
}

static int acsi_ioctl( struct inode *inode, struct file *file,
					   unsigned int cmd, unsigned long arg )
@@ -1086,18 +1099,6 @@ static int acsi_ioctl( struct inode *inode, struct file *file,
	struct gendisk *disk = inode->i_bdev->bd_disk;
	struct acsi_info_struct *aip = disk->private_data;
	switch (cmd) {
	  case HDIO_GETGEO:
		/* HDIO_GETGEO is supported more for getting the partition's
		 * start sector... */
	  { struct hd_geometry *geo = (struct hd_geometry *)arg;
	    /* just fake some geometry here, it's nonsense anyway; to make it
		 * easy, use Adaptec's usual 64/32 mapping */
	    put_user( 64, &geo->heads );
	    put_user( 32, &geo->sectors );
	    put_user( aip->size >> 11, &geo->cylinders );
		put_user(get_start_sect(inode->i_bdev), &geo->start);
		return 0;
	  }
	  case SCSI_IOCTL_GET_IDLUN:
		/* SCSI compatible GET_IDLUN call to get target's ID and LUN number */
		put_user( aip->target | (aip->lun << 8),
@@ -1592,6 +1593,7 @@ static struct block_device_operations acsi_fops = {
	.open		= acsi_open,
	.release	= acsi_release,
	.ioctl		= acsi_ioctl,
	.getgeo		= acsi_getgeo,
	.media_changed	= acsi_media_change,
	.revalidate_disk= acsi_revalidate,
};
Loading