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 2936b447cae9..2c0d0ec8150b 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
| @@ -55,6 +55,7 @@ | |||
| 55 | #include <linux/cpu.h> | 55 | #include <linux/cpu.h> |
| 56 | #include <linux/mutex.h> | 56 | #include <linux/mutex.h> |
| 57 | #include <linux/async.h> | 57 | #include <linux/async.h> |
| 58 | #include <asm/unaligned.h> | ||
| 58 | 59 | ||
| 59 | #include <scsi/scsi.h> | 60 | #include <scsi/scsi.h> |
| 60 | #include <scsi/scsi_cmnd.h> | 61 | #include <scsi/scsi_cmnd.h> |
| @@ -1062,6 +1063,50 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf, | |||
| 1062 | EXPORT_SYMBOL_GPL(scsi_get_vpd_page); | 1063 | EXPORT_SYMBOL_GPL(scsi_get_vpd_page); |
| 1063 | 1064 | ||
| 1064 | /** | 1065 | /** |
| 1066 | * scsi_report_opcode - Find out if a given command opcode is supported | ||
| 1067 | * @sdev: scsi device to query | ||
| 1068 | * @buffer: scratch buffer (must be at least 20 bytes long) | ||
| 1069 | * @len: length of buffer | ||
| 1070 | * @opcode: opcode for command to look up | ||
| 1071 | * | ||
| 1072 | * Uses the REPORT SUPPORTED OPERATION CODES to look up the given | ||
| 1073 | * opcode. Returns 0 if RSOC fails or if the command opcode is | ||
| 1074 | * unsupported. Returns 1 if the device claims to support the command. | ||
| 1075 | */ | ||
| 1076 | int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer, | ||
| 1077 | unsigned int len, unsigned char opcode) | ||
| 1078 | { | ||
| 1079 | unsigned char cmd[16]; | ||
| 1080 | struct scsi_sense_hdr sshdr; | ||
| 1081 | int result; | ||
| 1082 | |||
| 1083 | if (sdev->no_report_opcodes || sdev->scsi_level < SCSI_SPC_3) | ||
| 1084 | return 0; | ||
| 1085 | |||
| 1086 | memset(cmd, 0, 16); | ||
| 1087 | cmd[0] = MAINTENANCE_IN; | ||
| 1088 | cmd[1] = MI_REPORT_SUPPORTED_OPERATION_CODES; | ||
| 1089 | cmd[2] = 1; /* One command format */ | ||
| 1090 | cmd[3] = opcode; | ||
| 1091 | put_unaligned_be32(len, &cmd[6]); | ||
| 1092 | memset(buffer, 0, len); | ||
| 1093 | |||
| 1094 | result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len, | ||
| 1095 | &sshdr, 30 * HZ, 3, NULL); | ||
| 1096 | |||
| 1097 | if (result && scsi_sense_valid(&sshdr) && | ||
| 1098 | sshdr.sense_key == ILLEGAL_REQUEST && | ||
| 1099 | (sshdr.asc == 0x20 || sshdr.asc == 0x24) && sshdr.ascq == 0x00) | ||
| 1100 | return 0; | ||
| 1101 | |||
| 1102 | if ((buffer[1] & 3) == 3) /* Command supported */ | ||
| 1103 | return 1; | ||
| 1104 | |||
| 1105 | return 0; | ||
| 1106 | } | ||
| 1107 | EXPORT_SYMBOL(scsi_report_opcode); | ||
| 1108 | |||
| 1109 | /** | ||
| 1065 | * scsi_device_get - get an additional reference to a scsi_device | 1110 | * scsi_device_get - get an additional reference to a scsi_device |
| 1066 | * @sdev: device to get a reference to | 1111 | * @sdev: device to get a reference to |
| 1067 | * | 1112 | * |
