diff options
| -rw-r--r-- | drivers/ata/libata-scsi.c | 2 | ||||
| -rw-r--r-- | drivers/firewire/sbp2.c | 2 | ||||
| -rw-r--r-- | drivers/scsi/isci/request.c | 2 | ||||
| -rw-r--r-- | drivers/scsi/scsi.c | 45 | ||||
| -rw-r--r-- | drivers/scsi/scsi_lib.c | 22 | ||||
| -rw-r--r-- | drivers/scsi/sd.c | 202 | ||||
| -rw-r--r-- | drivers/scsi/sd.h | 7 | ||||
| -rw-r--r-- | drivers/usb/storage/scsiglue.c | 6 | ||||
| -rw-r--r-- | include/scsi/scsi_device.h | 4 |
9 files changed, 263 insertions, 29 deletions
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e3bda074fa12..a6df6a351d6e 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
| @@ -1052,6 +1052,8 @@ 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; | ||
| 1056 | sdev->no_write_same = 1; | ||
| 1055 | 1057 | ||
| 1056 | /* Schedule policy is determined by ->qc_defer() callback and | 1058 | /* Schedule policy is determined by ->qc_defer() callback and |
| 1057 | * it needs to see every deferred qc. Set dev_blocked to 1 to | 1059 | * 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..bb1b392f5cda 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c | |||
| @@ -1546,6 +1546,8 @@ 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; | ||
| 1550 | sdev->no_write_same = 1; | ||
| 1549 | 1551 | ||
| 1550 | if (sbp2_param_exclusive_login) | 1552 | if (sbp2_param_exclusive_login) |
| 1551 | sdev->manage_start_stop = 1; | 1553 | sdev->manage_start_stop = 1; |
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index c1bafc3f3fb1..9594ab62702b 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c | |||
| @@ -1972,7 +1972,7 @@ sci_io_request_frame_handler(struct isci_request *ireq, | |||
| 1972 | frame_index, | 1972 | frame_index, |
| 1973 | (void **)&frame_buffer); | 1973 | (void **)&frame_buffer); |
| 1974 | 1974 | ||
| 1975 | sci_controller_copy_sata_response(&ireq->stp.req, | 1975 | sci_controller_copy_sata_response(&ireq->stp.rsp, |
| 1976 | frame_header, | 1976 | frame_header, |
| 1977 | frame_buffer); | 1977 | frame_buffer); |
| 1978 | 1978 | ||
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/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index da36a3a81a9e..9032e910bca3 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
| @@ -900,11 +900,23 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) | |||
| 900 | action = ACTION_FAIL; | 900 | action = ACTION_FAIL; |
| 901 | error = -EILSEQ; | 901 | error = -EILSEQ; |
| 902 | /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */ | 902 | /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */ |
| 903 | } else if ((sshdr.asc == 0x20 || sshdr.asc == 0x24) && | 903 | } else if (sshdr.asc == 0x20 || sshdr.asc == 0x24) { |
| 904 | (cmd->cmnd[0] == UNMAP || | 904 | switch (cmd->cmnd[0]) { |
| 905 | cmd->cmnd[0] == WRITE_SAME_16 || | 905 | case UNMAP: |
| 906 | cmd->cmnd[0] == WRITE_SAME)) { | 906 | description = "Discard failure"; |
| 907 | description = "Discard failure"; | 907 | break; |
| 908 | case WRITE_SAME: | ||
| 909 | case WRITE_SAME_16: | ||
| 910 | if (cmd->cmnd[1] & 0x8) | ||
| 911 | description = "Discard failure"; | ||
| 912 | else | ||
| 913 | description = | ||
| 914 | "Write same failure"; | ||
| 915 | break; | ||
| 916 | default: | ||
| 917 | description = "Invalid command failure"; | ||
| 918 | break; | ||
| 919 | } | ||
| 908 | action = ACTION_FAIL; | 920 | action = ACTION_FAIL; |
| 909 | error = -EREMOTEIO; | 921 | error = -EREMOTEIO; |
| 910 | } else | 922 | } else |
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 12f6fdfc1147..352bc77b7c88 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
| @@ -99,6 +99,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC); | |||
| 99 | #endif | 99 | #endif |
| 100 | 100 | ||
| 101 | static void sd_config_discard(struct scsi_disk *, unsigned int); | 101 | static void sd_config_discard(struct scsi_disk *, unsigned int); |
| 102 | static void sd_config_write_same(struct scsi_disk *); | ||
| 102 | static int sd_revalidate_disk(struct gendisk *); | 103 | static int sd_revalidate_disk(struct gendisk *); |
| 103 | static void sd_unlock_native_capacity(struct gendisk *disk); | 104 | static void sd_unlock_native_capacity(struct gendisk *disk); |
| 104 | static int sd_probe(struct device *); | 105 | static int sd_probe(struct device *); |
| @@ -395,6 +396,45 @@ sd_store_max_medium_access_timeouts(struct device *dev, | |||
| 395 | return err ? err : count; | 396 | return err ? err : count; |
| 396 | } | 397 | } |
| 397 | 398 | ||
| 399 | static ssize_t | ||
| 400 | sd_show_write_same_blocks(struct device *dev, struct device_attribute *attr, | ||
| 401 | char *buf) | ||
| 402 | { | ||
| 403 | struct scsi_disk *sdkp = to_scsi_disk(dev); | ||
| 404 | |||
| 405 | return snprintf(buf, 20, "%u\n", sdkp->max_ws_blocks); | ||
| 406 | } | ||
| 407 | |||
| 408 | static ssize_t | ||
| 409 | sd_store_write_same_blocks(struct device *dev, struct device_attribute *attr, | ||
| 410 | const char *buf, size_t count) | ||
| 411 | { | ||
| 412 | struct scsi_disk *sdkp = to_scsi_disk(dev); | ||
| 413 | struct scsi_device *sdp = sdkp->device; | ||
| 414 | unsigned long max; | ||
| 415 | int err; | ||
| 416 | |||
| 417 | if (!capable(CAP_SYS_ADMIN)) | ||
| 418 | return -EACCES; | ||
| 419 | |||
| 420 | if (sdp->type != TYPE_DISK) | ||
| 421 | return -EINVAL; | ||
| 422 | |||
| 423 | err = kstrtoul(buf, 10, &max); | ||
| 424 | |||
| 425 | if (err) | ||
| 426 | return err; | ||
| 427 | |||
| 428 | if (max == 0) | ||
| 429 | sdp->no_write_same = 1; | ||
| 430 | else if (max <= SD_MAX_WS16_BLOCKS) | ||
| 431 | sdkp->max_ws_blocks = max; | ||
