Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 89877e42827f16fa5f86b1df0c2860b1 > files > 2108

kernel-2.6.18-128.1.10.el5.src.rpm

From: Tomas Henzl <thenzl@redhat.com>
Date: Tue, 26 Aug 2008 17:18:14 +0200
Subject: [scsi] cciss: support for sg_ioctl
Message-id: 48B41EB6.2020905@redhat.com
O-Subject: RHEL5.3 PATCH 2/2] support for sg_ioctl
Bugzilla: 250483

The patch comes from HP and adds c
It was backported from following upstream commits -
03bbfee58d440f5dc2e880944ab75fc644534794  add SG_IO ioctl to cciss
1a614f505193fcfc1b298643268a5db5b48e297f  fix error reporting for SG_IO

Resolves 250483 -  sg_io ioctl

Regards
Tomas

diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 8148f47..884d20f 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -46,6 +46,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.20-RH2)"
@@ -1222,6 +1225,32 @@ 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;
 	}
@@ -1235,7 +1264,7 @@ static inline void complete_buffers(struct bio *bio, int status)
 
 		bio->bi_next = NULL;
 		blk_finished_io(len);
-		bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO);
+		bio_endio(bio, nr_sectors << 9, status);
 		bio = xbh;
 	}
 }
@@ -2425,6 +2454,69 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
 	start_io(h);
 }
 
+static inline unsigned int make_status_bytes(unsigned int scsi_status_byte,
+			unsigned int msg_byte, unsigned int host_byte,
+			unsigned int driver_byte)
+{
+	/* inverse of macros in scsi.h */
+	return (scsi_status_byte & 0xff) |
+		((msg_byte & 0xff) << 8) |
+		((host_byte & 0xff) << 16) |
+		((driver_byte & 0xff) << 24);
+}
+
+static inline int evaluate_target_status(CommandList_struct *cmd)
+{
+	unsigned char sense_key;
+	unsigned char status_byte, msg_byte, host_byte, driver_byte;
+	int error_value;
+
+	/* If we get in here, it means we got "target status", that is, scsi status */
+	status_byte = cmd->err_info->ScsiStatus;
+	driver_byte = DRIVER_OK;
+	msg_byte = cmd->err_info->CommandStatus; /* correct?  seems too device specific */
+
+	if (blk_pc_request(cmd->rq))
+		host_byte = DID_PASSTHROUGH;
+	else
+		host_byte = DID_OK;
+
+	error_value = make_status_bytes(status_byte, msg_byte,
+		host_byte, driver_byte);
+
+	if (cmd->err_info->ScsiStatus != SAM_STAT_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 error_value;
+	}
+
+	/* check the sense key */
+	sense_key = 0xf & cmd->err_info->SenseInfo[2];
+	/* no status or recovered error */
+	if (((sense_key == 0x0) || (sense_key == 0x1)) && !blk_pc_request(cmd->rq))
+		error_value = 0;
+
+	if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */
+		if (error_value != 0)
+			printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION"
+			       " sense key = 0x%x\n", cmd, sense_key);
+		return error_value;
+	}
+
+	/* 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 error_value;
+}
+
 /* 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.
@@ -2432,109 +2524,122 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
 static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
 				    int timeout)
 {
-	int status = 1;
 	int retry_cmd = 0;
+	struct request *rq = cmd->rq;
+	int ctlr = h->ctlr;
 
+	rq->errors = 0;
 	if (timeout)
-		status = 0;
+		rq->errors = make_status_bytes(0, 0, 0, DRIVER_TIMEOUT);
 
-	if (cmd->err_info->CommandStatus != 0) {	/* an error has occurred */
-		switch (cmd->err_info->CommandStatus) {
-			unsigned char sense_key;
-		case CMD_TARGET_STATUS:
-			status = 0;
+	if (cmd->err_info->CommandStatus == 0)	/* no error has occurred */
+		goto after_error_processing;
 
-			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);
-			}
+	switch (cmd->err_info->CommandStatus) {
+		case CMD_TARGET_STATUS:
+			rq->errors = evaluate_target_status(cmd);
 			break;
 		case CMD_DATA_UNDERRUN:
-			printk(KERN_WARNING "cciss: cmd %p has"
-			       " completed with data underrun "
-			       "reported\n", cmd);
+			if (blk_fs_request(cmd->rq))
+				printk(KERN_WARNING "cciss: cmd %p has"
+				       " completed with data underrun "
+				       "reported\n", cmd);
 			break;
 		case CMD_DATA_OVERRUN:
-			printk(KERN_WARNING "cciss: cmd %p has"
-			       " completed with data overrun "
-			       "reported\n", cmd);
+			if (blk_fs_request(cmd->rq))
+				printk(KERN_WARNING "cciss: cmd %p has"
+				       " completed with data overrun "
+				       "reported\n", cmd);
 			break;
 		case CMD_INVALID:
 			printk(KERN_WARNING "cciss: cmd %p is "
 			       "reported invalid\n", cmd);
-			status = 0;
+			rq->errors = make_status_bytes(SAM_STAT_GOOD,
+				cmd->err_info->CommandStatus, DRIVER_OK,
+				blk_pc_request(cmd->rq) ? DID_PASSTHROUGH :
+				DID_ERROR);
 			break;
 		case CMD_PROTOCOL_ERR:
 			printk(KERN_WARNING "cciss: cmd %p has "
 			       "protocol error \n", cmd);
-			status = 0;
+			rq->errors = make_status_bytes(SAM_STAT_GOOD,
+				cmd->err_info->CommandStatus, DRIVER_OK,
+				blk_pc_request(cmd->rq) ? DID_PASSTHROUGH :
+				DID_ERROR);
 			break;
 		case CMD_HARDWARE_ERR:
-			printk(KERN_WARNING "cciss: cmd %p had "
-			       " hardware error\n", cmd);
-			status = 0;
+			printk(KERN_WARNING "cciss%d: cmd had "
+			       " hardware error\n", ctlr);
+			rq->errors = make_status_bytes(SAM_STAT_GOOD,
+				cmd->err_info->CommandStatus, DRIVER_OK,
+				blk_pc_request(cmd->rq) ? DID_PASSTHROUGH :
+				DID_ERROR);
 			break;
 		case CMD_CONNECTION_LOST:
-			printk(KERN_WARNING "cciss: cmd %p had "
-			       "connection lost\n", cmd);
-			status = 0;
+			printk(KERN_WARNING "cciss%d: cmd had "
+			       "connection lost\n", ctlr);
+			rq->errors = make_status_bytes(SAM_STAT_GOOD,
+				cmd->err_info->CommandStatus, DRIVER_OK,
+				blk_pc_request(cmd->rq) ? DID_PASSTHROUGH :
+				DID_ERROR);
 			break;
 		case CMD_ABORTED:
-			printk(KERN_WARNING "cciss: cmd %p was "
-			       "aborted\n", cmd);
-			status = 0;
+			printk(KERN_WARNING "cciss%d: cmd was "
+			       "aborted\n", ctlr);
+			rq->errors = make_status_bytes(SAM_STAT_GOOD,
+				cmd->err_info->CommandStatus, DRIVER_OK,
+				blk_pc_request(cmd->rq) ? DID_PASSTHROUGH :
+				DID_ABORT);
 			break;
 		case CMD_ABORT_FAILED:
-			printk(KERN_WARNING "cciss: cmd %p reports "
-			       "abort failed\n", cmd);
-			status = 0;
+			printk(KERN_WARNING "cciss%d: cmd reports "
+			       "abort failed\n", ctlr);
+			rq->errors = make_status_bytes(SAM_STAT_GOOD,
+				cmd->err_info->CommandStatus, DRIVER_OK,
+				blk_pc_request(cmd->rq) ? DID_PASSTHROUGH :
+				DID_ERROR);
 			break;
 		case CMD_UNSOLICITED_ABORT:
 			printk(KERN_WARNING "cciss%d: unsolicited "
-			       "abort %p\n", h->ctlr, cmd);
+			       "abort\n", ctlr);
 			if (cmd->retry_count < MAX_CMD_RETRIES) {
 				retry_cmd = 1;
 				printk(KERN_WARNING
-				       "cciss%d: retrying %p\n", h->ctlr, cmd);
+				       "cciss%d: retrying cmd\n", ctlr);
 				cmd->retry_count++;
 			} else
 				printk(KERN_WARNING
-				       "cciss%d: %p retried too "
-				       "many times\n", h->ctlr, cmd);
-			status = 0;
+				       "cciss%d: cmd retried too "
+				       "many times\n", ctlr);
+			rq->errors = make_status_bytes(SAM_STAT_GOOD,
+				cmd->err_info->CommandStatus, DRIVER_OK,
+				blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ABORT);
 			break;
 		case CMD_TIMEOUT:
-			printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd);
-			status = 0;
+			printk(KERN_WARNING "cciss%d: cmd timedout\n", ctlr);
+			rq->errors = make_status_bytes(SAM_STAT_GOOD,
+				cmd->err_info->CommandStatus, DRIVER_OK,
+				blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR);
 			break;
 		default:
-			printk(KERN_WARNING "cciss: cmd %p returned "
-			       "unknown status %x\n", cmd,
+			printk(KERN_WARNING "cciss%d: cmd returned "
+			       "unknown status %x\n", ctlr,
 			       cmd->err_info->CommandStatus);
-			status = 0;
-		}
+			rq->errors = make_status_bytes(SAM_STAT_GOOD,
+				cmd->err_info->CommandStatus, DRIVER_OK,
+				blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR);
 	}
-	/* We need to return this command */
+
+after_error_processing:
+
+	/* We need to retry this command */
 	if (retry_cmd) {
 		resend_cciss_cmd(h, cmd);
 		return;
 	}
 
+	cmd->rq->data_len = 0;
 	cmd->rq->completion_data = cmd;
-	cmd->rq->errors = status;
 	blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE);
 	blk_complete_request(cmd->rq);
 }
@@ -2629,34 +2734,42 @@ static void do_cciss_request(request_queue_t *q)
 
 	c->Header.SGList = c->Header.SGTotal = seg;
 
-	if(h->cciss_read == CCISS_READ_10) {
-		c->Request.CDB[1] = 0;
-		c->Request.CDB[2] = (start_blk >> 24) & 0xff;   //MSB
-		c->Request.CDB[3] = (start_blk >> 16) & 0xff;
-		c->Request.CDB[4] = (start_blk >> 8) & 0xff;
-		c->Request.CDB[5] = start_blk & 0xff;
-		c->Request.CDB[6] = 0;  // (sect >> 24) & 0xff; MSB
-		c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
-		c->Request.CDB[8] = creq->nr_sectors & 0xff;
-		c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
+	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
+			c->Request.CDB[3] = (start_blk >> 16) & 0xff;
+			c->Request.CDB[4] = (start_blk >> 8) & 0xff;
+			c->Request.CDB[5] = start_blk & 0xff;
+			c->Request.CDB[6] = 0;  // (sect >> 24) & 0xff; MSB
+			c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
+			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 {
-		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;
+		printk(KERN_WARNING "cciss%d: bad request type %ld\n",
+					h->ctlr, creq->flags);
+		BUG();
 	}
-
 	spin_lock_irq(q->queue_lock);
 
 	addQ(&(h->reqQ), c);
@@ -2665,9 +2778,9 @@ static void do_cciss_request(request_queue_t *q)
 		h->maxQsinceinit = h->Qdepth;
 
 	goto queue;
-      full:
+full:
 	blk_stop_queue(q);
-      startio:
+startio:
 	/* We will already have the driver lock here so not need
 	 * to lock it.
 	 */