diff options
Diffstat (limited to 'drivers/scsi/scsi.c')
| -rw-r--r-- | drivers/scsi/scsi.c | 45 | 
1 files changed, 45 insertions, 0 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 2936b447cae..2c0d0ec8150 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -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> @@ -1062,6 +1063,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   *  |