Commit 03bbfee5 authored by Mike Miller (OS Dev)'s avatar Mike Miller (OS Dev) Committed by Linus Torvalds
Browse files

cciss: add SG_IO ioctl to cciss



For all of you that think cciss should be a scsi driver here is the patch that
you have been waiting for all these years. This patch actually adds the SG_IO
ioctl to cciss. The primary purpose is for clustering and high-availibilty.
But now anyone can exploit this ioctl in any manner they wish.

Note, SCSI_IOCTL_SEND_COMMAND doesn't work with this patch due to rq->errors
being set incorrectly.  Subsequent patch fixes that.

Signed-off-by: default avatarStephen M. Cameron <steve.cameron@hp.com>
Signed-off-by: default avatarMike Miller <mike.miller@hp.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d38ae168
Loading
Loading
Loading
Loading
+111 −53
Original line number Diff line number Diff line
@@ -45,6 +45,9 @@
#include <linux/blkdev.h>
#include <linux/genhd.h>
#include <linux/completion.h>
#include <scsi/sg.h>
#include <scsi/scsi_ioctl.h>
#include <linux/cdrom.h>

#define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
#define DRIVER_NAME "HP CISS Driver (v 3.6.14)"
@@ -1152,6 +1155,30 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
			kfree(ioc);
			return status;
		}

	/* scsi_cmd_ioctl handles these, below, though some are not */
	/* very meaningful for cciss.  SG_IO is the main one people want. */

	case SG_GET_VERSION_NUM:
	case SG_SET_TIMEOUT:
	case SG_GET_TIMEOUT:
	case SG_GET_RESERVED_SIZE:
	case SG_SET_RESERVED_SIZE:
	case SG_EMULATED_HOST:
	case SG_IO:
	case SCSI_IOCTL_SEND_COMMAND:
		return scsi_cmd_ioctl(filep, disk, cmd, argp);

	/* scsi_cmd_ioctl would normally handle these, below, but */
	/* they aren't a good fit for cciss, as CD-ROMs are */
	/* not supported, and we don't have any bus/target/lun */
	/* which we present to the kernel. */

	case CDROM_SEND_PACKET:
	case CDROMCLOSETRAY:
	case CDROMEJECT:
	case SCSI_IOCTL_GET_IDLUN:
	case SCSI_IOCTL_GET_BUS_NUMBER:
	default:
		return -ENOTTY;
	}
@@ -2336,6 +2363,44 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
	start_io(h);
}

static inline int evaluate_target_status(CommandList_struct *cmd)
{
	unsigned char sense_key;
	int status = 0; /* 0 means bad, 1 means good. */

	if (cmd->err_info->ScsiStatus != 0x02) { /* not check condition? */
		if (!blk_pc_request(cmd->rq))
			printk(KERN_WARNING "cciss: cmd %p "
			       "has SCSI Status 0x%x\n",
			       cmd, cmd->err_info->ScsiStatus);
		return status;
	}

	/* check the sense key */
	sense_key = 0xf & cmd->err_info->SenseInfo[2];
	/* no status or recovered error */
	if ((sense_key == 0x0) || (sense_key == 0x1))
		status = 1;

	if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */
		if (status == 0)
			printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION"
			       " sense key = 0x%x\n", cmd, sense_key);
		return status;
	}

	/* SG_IO or similar, copy sense data back */
	if (cmd->rq->sense) {
		if (cmd->rq->sense_len > cmd->err_info->SenseLen)
			cmd->rq->sense_len = cmd->err_info->SenseLen;
		memcpy(cmd->rq->sense, cmd->err_info->SenseInfo,
			cmd->rq->sense_len);
	} else
		cmd->rq->sense_len = 0;

	return status;
}

/* checks the status of the job and calls complete buffers to mark all
 * buffers for the completed job. Note that this function does not need
 * to hold the hba/queue lock.
@@ -2353,34 +2418,19 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
		goto after_error_processing;

	switch (cmd->err_info->CommandStatus) {
		unsigned char sense_key;
	case CMD_TARGET_STATUS:
		status = 0;

		if (cmd->err_info->ScsiStatus == 0x02) {
			printk(KERN_WARNING "cciss: cmd %p "
			       "has CHECK CONDITION "
			       " byte 2 = 0x%x\n", cmd,
			       cmd->err_info->SenseInfo[2]
			    );
			/* check the sense key */
			sense_key = 0xf & cmd->err_info->SenseInfo[2];
			/* no status or recovered error */
			if ((sense_key == 0x0) || (sense_key == 0x1)) {
				status = 1;
			}
		} else {
			printk(KERN_WARNING "cciss: cmd %p "
			       "has SCSI Status 0x%x\n",
			       cmd, cmd->err_info->ScsiStatus);
		}
		status = evaluate_target_status(cmd);
		break;
	case CMD_DATA_UNDERRUN:
		if (blk_fs_request(cmd->rq)) {
			printk(KERN_WARNING "cciss: cmd %p has"
			       " completed with data underrun "
			       "reported\n", cmd);
			cmd->rq->data_len = cmd->err_info->ResidualCnt;
		}
		break;
	case CMD_DATA_OVERRUN:
		if (blk_fs_request(cmd->rq))
			printk(KERN_WARNING "cciss: cmd %p has"
			       " completed with data overrun "
			       "reported\n", cmd);
@@ -2447,9 +2497,9 @@ after_error_processing:
		resend_cciss_cmd(h, cmd);
		return;
	}

	cmd->rq->completion_data = cmd;
	cmd->rq->data_len = 0;
	cmd->rq->errors = status;
	cmd->rq->completion_data = cmd;
	blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE);
	blk_complete_request(cmd->rq);
}
@@ -2543,6 +2593,7 @@ static void do_cciss_request(request_queue_t *q)
#endif				/* CCISS_DEBUG */

	c->Header.SGList = c->Header.SGTotal = seg;
	if (likely(blk_fs_request(creq))) {
		if(h->cciss_read == CCISS_READ_10) {
			c->Request.CDB[1] = 0;
			c->Request.CDB[2] = (start_blk >> 24) & 0xff;	//MSB
@@ -2570,6 +2621,13 @@ static void do_cciss_request(request_queue_t *q)
			c->Request.CDB[13]= creq->nr_sectors & 0xff;
			c->Request.CDB[14] = c->Request.CDB[15] = 0;
		}
	} else if (blk_pc_request(creq)) {
		c->Request.CDBLen = creq->cmd_len;
		memcpy(c->Request.CDB, creq->cmd, BLK_MAX_CDB);
	} else {
		printk(KERN_WARNING "cciss%d: bad request type %d\n", h->ctlr, creq->cmd_type);
		BUG();
	}

	spin_lock_irq(q->queue_lock);