public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
* [RFC] generic scsi ioctls for character devices
@ 2003-05-23  8:33 Christoph Hellwig
  0 siblings, 0 replies; only message in thread
From: Christoph Hellwig @ 2003-05-23  8:33 UTC (permalink / raw)
  To: axboe; +Cc: linux-scsi

add a scsi_cmd_ioctl variant that works for character devices that have
a gendisk/queue.  It's a bit ugly because the fs/bio.c wants a struct
block_device * for each bio so we have to fake one up.  The codepathes
scsi_cmd_ioctl uses only ever looks into it's ->bd_queue though..


--- 1.26/drivers/block/scsi_ioctl.c	Wed May 14 12:22:25 2003
+++ edited/drivers/block/scsi_ioctl.c	Fri May 16 23:08:01 2003
@@ -45,13 +45,12 @@
 #define SCSI_SENSE_BUFFERSIZE 64
 #endif
 
-static int blk_do_rq(request_queue_t *q, struct block_device *bdev, 
-		     struct request *rq)
+static int blk_do_rq(struct gendisk *disk, struct request *rq)
 {
 	DECLARE_COMPLETION(wait);
 	int err = 0;
 
-	rq->rq_disk = bdev->bd_disk;
+	rq->rq_disk = disk;
 
 	/*
 	 * we need an extra reference to the request, so we can look at
@@ -62,8 +61,8 @@
 	rq->flags |= REQ_NOMERGE;
 	rq->waiting = &wait;
         drive_stat_acct(rq, rq->nr_sectors, 1);
-	elv_add_request(q, rq, 1, 1);
-	generic_unplug_device(q);
+	elv_add_request(disk->queue, rq, 1, 1);
+	generic_unplug_device(disk->queue);
 	wait_for_completion(&wait);
 
 	if (rq->errors)
@@ -80,12 +79,12 @@
 	return put_user(sg_version_num, p);
 }
 
-static int scsi_get_idlun(request_queue_t *q, int *p)
+static int scsi_get_idlun(int *p)
 {
 	return put_user(0, p);
 }
 
-static int scsi_get_bus(request_queue_t *q, int *p)
+static int scsi_get_bus(int *p)
 {
 	return put_user(0, p);
 }
@@ -124,14 +123,15 @@
  * will always return that we are ATAPI even for a real SCSI drive, I'm not
  * so sure this is worth doing anything about (why would you care??)
  */
-static int sg_emulated_host(request_queue_t *q, int *p)
+static int sg_emulated_host(int *p)
 {
 	return put_user(1, p);
 }
 
-static int sg_io(request_queue_t *q, struct block_device *bdev,
-		 struct sg_io_hdr *uptr)
+static int sg_io(struct gendisk *disk, struct sg_io_hdr *uptr,
+		struct block_device *bdev)
 {
+	struct request_queue *q = disk->queue;
 	unsigned long uaddr, start_time;
 	int reading, writing, nr_sectors;
 	struct sg_io_hdr hdr;
@@ -251,7 +251,7 @@
 	 * (if he doesn't check that is his problem).
 	 * N.B. a non-zero SCSI status is _not_ necessarily an error.
 	 */
-	blk_do_rq(q, bdev, rq);
+	blk_do_rq(disk, rq);
 
 	if (bio)
 		bio_unmap_user(bio, reading);
@@ -299,8 +299,7 @@
 #define READ_DEFECT_DATA_TIMEOUT	(60 * HZ )
 #define OMAX_SB_LEN 16          /* For backward compatibility */
 
-static int sg_scsi_ioctl(request_queue_t *q, struct block_device *bdev,
-			 Scsi_Ioctl_Command *sic)
+static int sg_scsi_ioctl(struct gendisk *disk, struct scsi_ioctl_command *sic)
 {
 	struct request *rq;
 	int err, in_len, out_len, bytes, opcode, cmdlen;
@@ -320,14 +319,14 @@
 
 	bytes = max(in_len, out_len);
 	if (bytes) {
-		buffer = kmalloc(bytes, q->bounce_gfp | GFP_USER);
+		buffer = kmalloc(bytes, disk->queue->bounce_gfp | GFP_USER);
 		if (!buffer)
 			return -ENOMEM;
 
 		memset(buffer, 0, bytes);
 	}
 
-	rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT);
+	rq = blk_get_request(disk->queue, in_len ? WRITE : READ, __GFP_WAIT);
 
 	cmdlen = COMMAND_SIZE(opcode);
 
@@ -372,7 +371,7 @@
 	rq->data_len = bytes;
 	rq->flags |= REQ_BLOCK_PC;
 
-	blk_do_rq(q, bdev, rq);
+	blk_do_rq(disk, rq);
 	err = rq->errors & 0xff;	/* only 8 bit SCSI status */
 	if (err) {
 		if (rq->sense_len && rq->sense) {
@@ -392,77 +391,98 @@
 	return err;
 }
 
-int scsi_cmd_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg)
+static int tray_ioctl(struct gendisk *disk, int close)
 {
-	request_queue_t *q;
-	struct request *rq;
-	int close = 0, err;
+	struct request *rq = blk_get_request(disk->queue, WRITE, __GFP_WAIT);
+	int error;
+
+	rq->flags = REQ_BLOCK_PC;
+	rq->data = NULL;
+	rq->data_len = 0;
+	rq->timeout = BLK_DEFAULT_TIMEOUT;
+	memset(rq->cmd, 0, sizeof(rq->cmd));
+	rq->cmd[0] = GPCMD_START_STOP_UNIT;
+	rq->cmd[4] = 0x02 + (close != 0);
+	rq->cmd_len = 6;
+	error = blk_do_rq(disk, rq);
+	blk_put_request(rq);
+
+	return error;
+}
 
-	q = bdev_get_queue(bdev);
-	if (!q)
-		return -ENXIO;
+static int __scsi_cmd_ioctl(struct block_device *bdev,
+		unsigned int cmd, unsigned long arg)
+{
+	struct gendisk *disk = bdev->bd_disk;
+	struct request_queue *q = disk->queue;
 
 	switch (cmd) {
-		/*
-		 * new sgv3 interface
-		 */
-		case SG_GET_VERSION_NUM:
-			return sg_get_version((int *) arg);
-		case SCSI_IOCTL_GET_IDLUN:
-			return scsi_get_idlun(q, (int *) arg);
-		case SCSI_IOCTL_GET_BUS_NUMBER:
-			return scsi_get_bus(q, (int *) arg);
-		case SG_SET_TIMEOUT:
-			return sg_set_timeout(q, (int *) arg);
-		case SG_GET_TIMEOUT:
-			return sg_get_timeout(q);
-		case SG_GET_RESERVED_SIZE:
-			return sg_get_reserved_size(q, (int *) arg);
-		case SG_SET_RESERVED_SIZE:
-			return sg_set_reserved_size(q, (int *) arg);
-		case SG_EMULATED_HOST:
-			return sg_emulated_host(q, (int *) arg);
-		case SG_IO:
-			err = bd_claim(bdev, current);
-			if (err)
-				break;
-			err = sg_io(q, bdev, (struct sg_io_hdr *) arg);
-			bd_release(bdev);
-			break;
-		/*
-		 * old junk scsi send command ioctl
-		 */
-		case SCSI_IOCTL_SEND_COMMAND:
-			if (!arg)
-				return -EINVAL;
-
-			err = bd_claim(bdev, current);
-			if (err)
-				break;
-			err = sg_scsi_ioctl(q, bdev, (Scsi_Ioctl_Command *)arg);
+	/*
+	 * new sgv3 interface
+	 */
+	case SG_GET_VERSION_NUM:
+		return sg_get_version((int *) arg);
+	case SCSI_IOCTL_GET_IDLUN:
+		return scsi_get_idlun((int *) arg);
+	case SCSI_IOCTL_GET_BUS_NUMBER:
+		return scsi_get_bus((int *) arg);
+	case SG_SET_TIMEOUT:
+		return sg_set_timeout(q, (int *) arg);
+	case SG_GET_TIMEOUT:
+		return sg_get_timeout(q);
+	case SG_GET_RESERVED_SIZE:
+		return sg_get_reserved_size(q, (int *) arg);
+	case SG_SET_RESERVED_SIZE:
+		return sg_set_reserved_size(q, (int *) arg);
+	case SG_EMULATED_HOST:
+		return sg_emulated_host((int *) arg);
+	case SG_IO:
+		return sg_io(disk, (struct sg_io_hdr *)arg, bdev);
+	/*
+	 * old junk scsi send command ioctl
+	 */
+	case SCSI_IOCTL_SEND_COMMAND:
+		return sg_scsi_ioctl(disk, (struct scsi_ioctl_command *)arg);
+	/*
+	 * CDROM ioctls.
+	 */
+	case CDROMCLOSETRAY:
+		return tray_ioctl(disk, 1);
+	case CDROMEJECT:
+		return tray_ioctl(disk, 0);
+
+	default:
+		return -ENOTTY;
+	}
+}
+
+int scsi_cmd_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg)
+{
+	int error;
+
+	switch (cmd) {
+	case SG_IO:
+	case SCSI_IOCTL_SEND_COMMAND:
+		error = bd_claim(bdev, current);
+		if (!error) {
+			error = __scsi_cmd_ioctl(bdev, cmd, arg);
 			bd_release(bdev);
-			break;
-		case CDROMCLOSETRAY:
-			close = 1;
-		case CDROMEJECT:
-			rq = blk_get_request(q, WRITE, __GFP_WAIT);
-			rq->flags = REQ_BLOCK_PC;
-			rq->data = NULL;
-			rq->data_len = 0;
-			rq->timeout = BLK_DEFAULT_TIMEOUT;
-			memset(rq->cmd, 0, sizeof(rq->cmd));
-			rq->cmd[0] = GPCMD_START_STOP_UNIT;
-			rq->cmd[4] = 0x02 + (close != 0);
-			rq->cmd_len = 6;
-			err = blk_do_rq(q, bdev, rq);
-			blk_put_request(rq);
-			break;
-		default:
-			err = -ENOTTY;
+		}
+
+		return error;
 	}
 
-	blk_put_queue(q);
-	return err;
+	return __scsi_cmd_ioctl(bdev, cmd, arg);
+}
+
+int scsi_cmd_ioctl_chrdev(struct gendisk *disk, unsigned int cmd, unsigned long arg)
+{
+	struct block_device fake_bdev;
+
+	memset(&fake_bdev, 0x0e, sizeof(fake_bdev));
+	fake_bdev.bd_disk = disk;
+
+	return __scsi_cmd_ioctl(&fake_bdev, cmd, arg);
 }
 
 EXPORT_SYMBOL(scsi_cmd_ioctl);

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2003-05-23  8:20 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-05-23  8:33 [RFC] generic scsi ioctls for character devices Christoph Hellwig

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox