Skip to content

Commit

Permalink
Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/g…
Browse files Browse the repository at this point in the history
…it/jejb/scsi

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: James Bottomley <JBottomley@Parallels.com>"

* 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
  • Loading branch information
Linus Torvalds committed Nov 22, 2012
2 parents 0e0f092 + 5db4486 commit a2d2eda
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 29 deletions.
2 changes: 2 additions & 0 deletions drivers/ata/libata-scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions drivers/firewire/sbp2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion drivers/scsi/isci/request.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
45 changes: 45 additions & 0 deletions drivers/scsi/scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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
Expand Down
22 changes: 17 additions & 5 deletions drivers/scsi/scsi_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
description = "Discard failure";
} 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
Expand Down
Loading

0 comments on commit a2d2eda

Please sign in to comment.