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: Stephen M. Cameron <steve.cameron@hp.com> Signed-off-by: Mike Miller <mike.miller@hp.com> Cc: James Bottomley <James.Bottomley@steeleye.com> Cc: Jens Axboe <jens.axboe@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
d38ae168bf
commit
03bbfee58d
|
@ -45,6 +45,9 @@
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
#include <linux/genhd.h>
|
#include <linux/genhd.h>
|
||||||
#include <linux/completion.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 CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
|
||||||
#define DRIVER_NAME "HP CISS Driver (v 3.6.14)"
|
#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);
|
kfree(ioc);
|
||||||
return status;
|
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:
|
default:
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
}
|
}
|
||||||
|
@ -2336,6 +2363,44 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
|
||||||
start_io(h);
|
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
|
/* 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
|
* buffers for the completed job. Note that this function does not need
|
||||||
* to hold the hba/queue lock.
|
* to hold the hba/queue lock.
|
||||||
|
@ -2353,37 +2418,22 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
|
||||||
goto after_error_processing;
|
goto after_error_processing;
|
||||||
|
|
||||||
switch (cmd->err_info->CommandStatus) {
|
switch (cmd->err_info->CommandStatus) {
|
||||||
unsigned char sense_key;
|
|
||||||
case CMD_TARGET_STATUS:
|
case CMD_TARGET_STATUS:
|
||||||
status = 0;
|
status = evaluate_target_status(cmd);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case CMD_DATA_UNDERRUN:
|
case CMD_DATA_UNDERRUN:
|
||||||
printk(KERN_WARNING "cciss: cmd %p has"
|
if (blk_fs_request(cmd->rq)) {
|
||||||
" completed with data underrun "
|
printk(KERN_WARNING "cciss: cmd %p has"
|
||||||
"reported\n", cmd);
|
" completed with data underrun "
|
||||||
|
"reported\n", cmd);
|
||||||
|
cmd->rq->data_len = cmd->err_info->ResidualCnt;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CMD_DATA_OVERRUN:
|
case CMD_DATA_OVERRUN:
|
||||||
printk(KERN_WARNING "cciss: cmd %p has"
|
if (blk_fs_request(cmd->rq))
|
||||||
" completed with data overrun "
|
printk(KERN_WARNING "cciss: cmd %p has"
|
||||||
"reported\n", cmd);
|
" completed with data overrun "
|
||||||
|
"reported\n", cmd);
|
||||||
break;
|
break;
|
||||||
case CMD_INVALID:
|
case CMD_INVALID:
|
||||||
printk(KERN_WARNING "cciss: cmd %p is "
|
printk(KERN_WARNING "cciss: cmd %p is "
|
||||||
|
@ -2447,9 +2497,9 @@ after_error_processing:
|
||||||
resend_cciss_cmd(h, cmd);
|
resend_cciss_cmd(h, cmd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
cmd->rq->data_len = 0;
|
||||||
cmd->rq->completion_data = cmd;
|
|
||||||
cmd->rq->errors = status;
|
cmd->rq->errors = status;
|
||||||
|
cmd->rq->completion_data = cmd;
|
||||||
blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE);
|
blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE);
|
||||||
blk_complete_request(cmd->rq);
|
blk_complete_request(cmd->rq);
|
||||||
}
|
}
|
||||||
|
@ -2543,32 +2593,40 @@ static void do_cciss_request(request_queue_t *q)
|
||||||
#endif /* CCISS_DEBUG */
|
#endif /* CCISS_DEBUG */
|
||||||
|
|
||||||
c->Header.SGList = c->Header.SGTotal = seg;
|
c->Header.SGList = c->Header.SGTotal = seg;
|
||||||
if(h->cciss_read == CCISS_READ_10) {
|
if (likely(blk_fs_request(creq))) {
|
||||||
c->Request.CDB[1] = 0;
|
if(h->cciss_read == CCISS_READ_10) {
|
||||||
c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB
|
c->Request.CDB[1] = 0;
|
||||||
c->Request.CDB[3] = (start_blk >> 16) & 0xff;
|
c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB
|
||||||
c->Request.CDB[4] = (start_blk >> 8) & 0xff;
|
c->Request.CDB[3] = (start_blk >> 16) & 0xff;
|
||||||
c->Request.CDB[5] = start_blk & 0xff;
|
c->Request.CDB[4] = (start_blk >> 8) & 0xff;
|
||||||
c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB
|
c->Request.CDB[5] = start_blk & 0xff;
|
||||||
c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
|
c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB
|
||||||
c->Request.CDB[8] = creq->nr_sectors & 0xff;
|
c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
|
||||||
c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
|
c->Request.CDB[8] = creq->nr_sectors & 0xff;
|
||||||
|
c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
|
||||||
|
} else {
|
||||||
|
c->Request.CDBLen = 16;
|
||||||
|
c->Request.CDB[1]= 0;
|
||||||
|
c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB
|
||||||
|
c->Request.CDB[3]= (start_blk >> 48) & 0xff;
|
||||||
|
c->Request.CDB[4]= (start_blk >> 40) & 0xff;
|
||||||
|
c->Request.CDB[5]= (start_blk >> 32) & 0xff;
|
||||||
|
c->Request.CDB[6]= (start_blk >> 24) & 0xff;
|
||||||
|
c->Request.CDB[7]= (start_blk >> 16) & 0xff;
|
||||||
|
c->Request.CDB[8]= (start_blk >> 8) & 0xff;
|
||||||
|
c->Request.CDB[9]= start_blk & 0xff;
|
||||||
|
c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff;
|
||||||
|
c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff;
|
||||||
|
c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff;
|
||||||
|
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 {
|
} else {
|
||||||
c->Request.CDBLen = 16;
|
printk(KERN_WARNING "cciss%d: bad request type %d\n", h->ctlr, creq->cmd_type);
|
||||||
c->Request.CDB[1]= 0;
|
BUG();
|
||||||
c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB
|
|
||||||
c->Request.CDB[3]= (start_blk >> 48) & 0xff;
|
|
||||||
c->Request.CDB[4]= (start_blk >> 40) & 0xff;
|
|
||||||
c->Request.CDB[5]= (start_blk >> 32) & 0xff;
|
|
||||||
c->Request.CDB[6]= (start_blk >> 24) & 0xff;
|
|
||||||
c->Request.CDB[7]= (start_blk >> 16) & 0xff;
|
|
||||||
c->Request.CDB[8]= (start_blk >> 8) & 0xff;
|
|
||||||
c->Request.CDB[9]= start_blk & 0xff;
|
|
||||||
c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff;
|
|
||||||
c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff;
|
|
||||||
c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff;
|
|
||||||
c->Request.CDB[13]= creq->nr_sectors & 0xff;
|
|
||||||
c->Request.CDB[14] = c->Request.CDB[15] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irq(q->queue_lock);
|
spin_lock_irq(q->queue_lock);
|
||||||
|
|
Loading…
Reference in a new issue