patch-2.4.7 linux/drivers/scsi/scsi_ioctl.c

Next file: linux/drivers/scsi/scsi_lib.c
Previous file: linux/drivers/scsi/scsi_error.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
@@ -79,7 +79,7 @@
  * 
  * *(char *) ((int *) arg)[2] the actual command byte.   
  * 
- * Note that if more than MAX_BUF bytes are requested to be transfered,
+ * Note that if more than MAX_BUF bytes are requested to be transferred,
  * the ioctl will fail with error EINVAL.  MAX_BUF can be increased in
  * the future by increasing the size that scsi_malloc will accept.
  * 
@@ -196,8 +196,8 @@
 	Scsi_Request *SRpnt;
 	Scsi_Device *SDpnt;
 	unsigned char opcode;
-	int inlen, outlen, cmdlen;
-	int needed, buf_needed;
+	unsigned int inlen, outlen, cmdlen;
+	unsigned int needed, buf_needed;
 	int timeout, retries, result;
 	int data_direction;
 
@@ -209,8 +209,11 @@
 	if (verify_area(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command)))
 		return -EFAULT;
 
-	__get_user(inlen, &sic->inlen);
-	__get_user(outlen, &sic->outlen);
+	if(__get_user(inlen, &sic->inlen))
+		return -EFAULT;
+		
+	if(__get_user(outlen, &sic->outlen))
+		return -EFAULT;
 
 	/*
 	 * We do not transfer more than MAX_BUF with this interface.
@@ -223,7 +226,8 @@
 		return -EINVAL;
 
 	cmd_in = sic->data;
-	__get_user(opcode, cmd_in);
+	if(get_user(opcode, cmd_in))
+		return -EFAULT;
 
 	needed = buf_needed = (inlen > outlen ? inlen : outlen);
 	if (buf_needed) {
@@ -254,21 +258,27 @@
 	 * Obtain the command from the user's address space.
 	 */
 	cmdlen = COMMAND_SIZE(opcode);
+	
+	result = -EFAULT;
 
 	if (verify_area(VERIFY_READ, cmd_in, cmdlen + inlen))
-		return -EFAULT;
+		goto error;
 
-	__copy_from_user(cmd, cmd_in, cmdlen);
+	if(__copy_from_user(cmd, cmd_in, cmdlen))
+		goto error;
 
 	/*
 	 * Obtain the data to be sent to the device (if any).
 	 */
-	__copy_from_user(buf, cmd_in + cmdlen, inlen);
+
+	if(copy_from_user(buf, cmd_in + cmdlen, inlen))
+		goto error;
 
 	/*
 	 * Set the lun field to the correct value.
 	 */
-	cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5);
+	if (dev->scsi_level <= SCSI_2)
+		cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5);
 
 	switch (opcode) {
 	case FORMAT_UNIT:
@@ -303,7 +313,8 @@
 	SRpnt = scsi_allocate_request(dev);
         if( SRpnt == NULL )
         {
-                return -EINTR;
+                result = -EINTR;
+                goto error;
         }
 
 	SRpnt->sr_data_direction = data_direction;
@@ -312,7 +323,9 @@
 	/* 
 	 * If there was an error condition, pass the info back to the user. 
 	 */
+
 	result = SRpnt->sr_result;
+
 	if (SRpnt->sr_result) {
 		int sb_len = sizeof(SRpnt->sr_sense_buffer);
 
@@ -322,12 +335,13 @@
 	} else {
 		if (copy_to_user(cmd_in, buf, outlen))
 			result = -EFAULT;
-	}
+	}	
 
 	SDpnt = SRpnt->sr_device;
 	scsi_release_request(SRpnt);
 	SRpnt = NULL;
 
+error:
 	if (buf)
 		scsi_free(buf, buf_needed);
 
@@ -379,6 +393,7 @@
 int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
 {
 	char scsi_cmd[MAX_COMMAND_SIZE];
+	char cmd_byte1;
 
 	/* No idea how this happens.... */
 	if (!dev)
@@ -393,14 +408,16 @@
 	if (!scsi_block_when_processing_errors(dev)) {
 		return -ENODEV;
 	}
+	cmd_byte1 = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0;
+
 	switch (cmd) {
 	case SCSI_IOCTL_GET_IDLUN:
 		if (verify_area(VERIFY_WRITE, arg, sizeof(Scsi_Idlun)))
 			return -EFAULT;
 
-		__put_user(dev->id
-			 + (dev->lun << 8)
-			 + (dev->channel << 16)
+		__put_user((dev->id & 0xff)
+			 + ((dev->lun & 0xff) << 8)
+			 + ((dev->channel & 0xff) << 16)
 			 + ((dev->host->host_no & 0xff) << 24),
 			 &((Scsi_Idlun *) arg)->dev_id);
 		__put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id);
@@ -434,7 +451,7 @@
 		if (!dev->removable || !dev->lockable)
 			return 0;
 		scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
-		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[1] = cmd_byte1;
 		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
 		scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
 		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
@@ -444,14 +461,14 @@
 		if (!dev->removable || !dev->lockable)
 			return 0;
 		scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
-		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[1] = cmd_byte1;
 		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
 		scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
 		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
 				   IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
 	case SCSI_IOCTL_TEST_UNIT_READY:
 		scsi_cmd[0] = TEST_UNIT_READY;
-		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[1] = cmd_byte1;
 		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
 		scsi_cmd[4] = 0;
 		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
@@ -459,7 +476,7 @@
 		break;
 	case SCSI_IOCTL_START_UNIT:
 		scsi_cmd[0] = START_STOP;
-		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[1] = cmd_byte1;
 		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
 		scsi_cmd[4] = 1;
 		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
@@ -467,7 +484,7 @@
 		break;
 	case SCSI_IOCTL_STOP_UNIT:
 		scsi_cmd[0] = START_STOP;
-		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[1] = cmd_byte1;
 		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
 		scsi_cmd[4] = 0;
 		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)