Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a2d2eda7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files


Pull SCSI fixes from James Bottomley:
 "This is a set of four bug fixes.

  The isci one is an obvious thinko (using request buffer instead of
  response buffer) which causes a command to fail.

  The three others are DIF/DIX updates which are required because
  they're part of a series of ten patches, the other seven of which went
  into the block layer during the merge window meaning our current
  DIF/DIX implementation is broken without these three.

  Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com&gt;">

* tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
  [SCSI] sd: Implement support for WRITE SAME
  [SCSI] sd: Permit merged discard requests
  [SCSI] Add a report opcode helper
  [SCSI] isci: copy fis 0x34 response into proper buffer
parents 0e0f092e 5db44863
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1052,6 +1052,8 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev)
{
	sdev->use_10_for_rw = 1;
	sdev->use_10_for_ms = 1;
	sdev->no_report_opcodes = 1;
	sdev->no_write_same = 1;

	/* Schedule policy is determined by ->qc_defer() callback and
	 * it needs to see every deferred qc.  Set dev_blocked to 1 to
+2 −0
Original line number Diff line number Diff line
@@ -1546,6 +1546,8 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
	struct sbp2_logical_unit *lu = sdev->hostdata;

	sdev->use_10_for_rw = 1;
	sdev->no_report_opcodes = 1;
	sdev->no_write_same = 1;

	if (sbp2_param_exclusive_login)
		sdev->manage_start_stop = 1;
+1 −1
Original line number Diff line number Diff line
@@ -1972,7 +1972,7 @@ sci_io_request_frame_handler(struct isci_request *ireq,
								      frame_index,
								      (void **)&frame_buffer);

			sci_controller_copy_sata_response(&ireq->stp.req,
			sci_controller_copy_sata_response(&ireq->stp.rsp,
							       frame_header,
							       frame_buffer);

+45 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@
#include <linux/cpu.h>
#include <linux/mutex.h>
#include <linux/async.h>
#include <asm/unaligned.h>

#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -1061,6 +1062,50 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
}
EXPORT_SYMBOL_GPL(scsi_get_vpd_page);

/**
 * scsi_report_opcode - Find out if a given command opcode is supported
 * @sdev:	scsi device to query
 * @buffer:	scratch buffer (must be at least 20 bytes long)
 * @len:	length of buffer
 * @opcode:	opcode for command to look up
 *
 * Uses the REPORT SUPPORTED OPERATION CODES to look up the given
 * opcode. Returns 0 if RSOC fails or if the command opcode is
 * unsupported. Returns 1 if the device claims to support the command.
 */
int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
		       unsigned int len, unsigned char opcode)
{
	unsigned char cmd[16];
	struct scsi_sense_hdr sshdr;
	int result;

	if (sdev->no_report_opcodes || sdev->scsi_level < SCSI_SPC_3)
		return 0;

	memset(cmd, 0, 16);
	cmd[0] = MAINTENANCE_IN;
	cmd[1] = MI_REPORT_SUPPORTED_OPERATION_CODES;
	cmd[2] = 1;		/* One command format */
	cmd[3] = opcode;
	put_unaligned_be32(len, &cmd[6]);
	memset(buffer, 0, len);

	result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len,
				  &sshdr, 30 * HZ, 3, NULL);

	if (result && scsi_sense_valid(&sshdr) &&
	    sshdr.sense_key == ILLEGAL_REQUEST &&
	    (sshdr.asc == 0x20 || sshdr.asc == 0x24) && sshdr.ascq == 0x00)
		return 0;

	if ((buffer[1] & 3) == 3) /* Command supported */
		return 1;

	return 0;
}
EXPORT_SYMBOL(scsi_report_opcode);

/**
 * scsi_device_get  -  get an additional reference to a scsi_device
 * @sdev:	device to get a reference to
+17 −5
Original line number Diff line number Diff line
@@ -900,11 +900,23 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
				action = ACTION_FAIL;
				error = -EILSEQ;
			/* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */
			} else if ((sshdr.asc == 0x20 || sshdr.asc == 0x24) &&
				   (cmd->cmnd[0] == UNMAP ||
				    cmd->cmnd[0] == WRITE_SAME_16 ||
				    cmd->cmnd[0] == WRITE_SAME)) {
			} else if (sshdr.asc == 0x20 || sshdr.asc == 0x24) {
				switch (cmd->cmnd[0]) {
				case UNMAP:
					description = "Discard failure";
					break;
				case WRITE_SAME:
				case WRITE_SAME_16:
					if (cmd->cmnd[1] & 0x8)
						description = "Discard failure";
					else
						description =
							"Write same failure";
					break;
				default:
					description = "Invalid command failure";
					break;
				}
				action = ACTION_FAIL;
				error = -EREMOTEIO;
			} else
Loading