diff options
-rw-r--r-- | drivers/ata/libata-scsi.c | 1 | ||||
-rw-r--r-- | drivers/firewire/sbp2.c | 1 | ||||
-rw-r--r-- | drivers/scsi/scsi.c | 45 | ||||
-rw-r--r-- | drivers/usb/storage/scsiglue.c | 3 | ||||
-rw-r--r-- | include/scsi/scsi_device.h | 3 |
5 files changed, 53 insertions, 0 deletions
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e3bda074fa12..7c2dead60518 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
@@ -1052,6 +1052,7 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev) | |||
1052 | { | 1052 | { |
1053 | sdev->use_10_for_rw = 1; | 1053 | sdev->use_10_for_rw = 1; |
1054 | sdev->use_10_for_ms = 1; | 1054 | sdev->use_10_for_ms = 1; |
1055 | sdev->no_report_opcodes = 1; | ||
1055 | 1056 | ||
1056 | /* Schedule policy is determined by ->qc_defer() callback and | 1057 | /* Schedule policy is determined by ->qc_defer() callback and |
1057 | * it needs to see every deferred qc. Set dev_blocked to 1 to | 1058 | * it needs to see every deferred qc. Set dev_blocked to 1 to |
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 1162d6b3bf85..f82e9d4295d0 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c | |||
@@ -1546,6 +1546,7 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev) | |||
1546 | struct sbp2_logical_unit *lu = sdev->hostdata; | 1546 | struct sbp2_logical_unit *lu = sdev->hostdata; |
1547 | 1547 | ||
1548 | sdev->use_10_for_rw = 1; | 1548 | sdev->use_10_for_rw = 1; |
1549 | sdev->no_report_opcodes = 1; | ||
1549 | 1550 | ||
1550 | if (sbp2_param_exclusive_login) | 1551 | if (sbp2_param_exclusive_login) |
1551 | sdev->manage_start_stop = 1; | 1552 | sdev->manage_start_stop = 1; |
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 | * |
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index a3d54366afcc..6ab376a7c501 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c | |||
@@ -186,6 +186,9 @@ static int slave_configure(struct scsi_device *sdev) | |||
186 | /* Some devices don't handle VPD pages correctly */ | 186 | /* Some devices don't handle VPD pages correctly */ |
187 | sdev->skip_vpd_pages = 1; | 187 | sdev->skip_vpd_pages = 1; |
188 | 188 | ||
189 | /* Do not attempt to use REPORT SUPPORTED OPERATION CODES */ | ||
190 | sdev->no_report_opcodes = 1; | ||
191 | |||
189 | /* Some disks return the total number of blocks in response | 192 | /* Some disks return the total number of blocks in response |
190 | * to READ CAPACITY rather than the highest block number. | 193 | * to READ CAPACITY rather than the highest block number. |
191 | * If this device makes that mistake, tell the sd driver. */ | 194 | * If this device makes that mistake, tell the sd driver. */ |
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 88fae8d20154..379d465e8070 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h | |||
@@ -135,6 +135,7 @@ struct scsi_device { | |||
135 | * because we did a bus reset. */ | 135 | * because we did a bus reset. */ |
136 | unsigned use_10_for_rw:1; /* first try 10-byte read / write */ | 136 | unsigned use_10_for_rw:1; /* first try 10-byte read / write */ |
137 | unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ | 137 | unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ |
138 | unsigned no_report_opcodes:1; /* no REPORT SUPPORTED OPERATION CODES */ | ||
138 | unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */ | 139 | unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */ |
139 | unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */ | 140 | unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */ |
140 | unsigned skip_vpd_pages:1; /* do not read VPD pages */ | 141 | unsigned skip_vpd_pages:1; /* do not read VPD pages */ |
@@ -362,6 +363,8 @@ extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, | |||
362 | int retries, struct scsi_sense_hdr *sshdr); | 363 | int retries, struct scsi_sense_hdr *sshdr); |
363 | extern int scsi_get_vpd_page(struct scsi_device *, u8 page, unsigned char *buf, | 364 | extern int scsi_get_vpd_page(struct scsi_device *, u8 page, unsigned char *buf, |
364 | int buf_len); | 365 | int buf_len); |
366 | extern int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer, | ||
367 | unsigned int len, unsigned char opcode); | ||
365 | extern int scsi_device_set_state(struct scsi_device *sdev, | 368 | extern int scsi_device_set_state(struct scsi_device *sdev, |
366 | enum scsi_device_state state); | 369 | enum scsi_device_state state); |
367 | extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type, | 370 | extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type, |