diff options
Diffstat (limited to 'drivers/scsi/sd.c')
| -rw-r--r-- | drivers/scsi/sd.c | 169 |
1 files changed, 88 insertions, 81 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index ea38757d12e5..3225d31449e1 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
| @@ -207,6 +207,23 @@ static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf, | |||
| 207 | return count; | 207 | return count; |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | static ssize_t sd_store_allow_restart(struct class_device *cdev, const char *buf, | ||
| 211 | size_t count) | ||
| 212 | { | ||
| 213 | struct scsi_disk *sdkp = to_scsi_disk(cdev); | ||
| 214 | struct scsi_device *sdp = sdkp->device; | ||
| 215 | |||
| 216 | if (!capable(CAP_SYS_ADMIN)) | ||
| 217 | return -EACCES; | ||
| 218 | |||
| 219 | if (sdp->type != TYPE_DISK) | ||
| 220 | return -EINVAL; | ||
| 221 | |||
| 222 | sdp->allow_restart = simple_strtoul(buf, NULL, 10); | ||
| 223 | |||
| 224 | return count; | ||
| 225 | } | ||
| 226 | |||
| 210 | static ssize_t sd_show_cache_type(struct class_device *cdev, char *buf) | 227 | static ssize_t sd_show_cache_type(struct class_device *cdev, char *buf) |
| 211 | { | 228 | { |
| 212 | struct scsi_disk *sdkp = to_scsi_disk(cdev); | 229 | struct scsi_disk *sdkp = to_scsi_disk(cdev); |
| @@ -222,10 +239,19 @@ static ssize_t sd_show_fua(struct class_device *cdev, char *buf) | |||
| 222 | return snprintf(buf, 20, "%u\n", sdkp->DPOFUA); | 239 | return snprintf(buf, 20, "%u\n", sdkp->DPOFUA); |
| 223 | } | 240 | } |
| 224 | 241 | ||
| 242 | static ssize_t sd_show_allow_restart(struct class_device *cdev, char *buf) | ||
| 243 | { | ||
| 244 | struct scsi_disk *sdkp = to_scsi_disk(cdev); | ||
| 245 | |||
| 246 | return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart); | ||
| 247 | } | ||
| 248 | |||
| 225 | static struct class_device_attribute sd_disk_attrs[] = { | 249 | static struct class_device_attribute sd_disk_attrs[] = { |
| 226 | __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, | 250 | __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, |
| 227 | sd_store_cache_type), | 251 | sd_store_cache_type), |
| 228 | __ATTR(FUA, S_IRUGO, sd_show_fua, NULL), | 252 | __ATTR(FUA, S_IRUGO, sd_show_fua, NULL), |
| 253 | __ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart, | ||
| 254 | sd_store_allow_restart), | ||
| 229 | __ATTR_NULL, | 255 | __ATTR_NULL, |
| 230 | }; | 256 | }; |
| 231 | 257 | ||
| @@ -890,11 +916,10 @@ static struct block_device_operations sd_fops = { | |||
| 890 | static void sd_rw_intr(struct scsi_cmnd * SCpnt) | 916 | static void sd_rw_intr(struct scsi_cmnd * SCpnt) |
| 891 | { | 917 | { |
| 892 | int result = SCpnt->result; | 918 | int result = SCpnt->result; |
| 893 | int this_count = SCpnt->request_bufflen; | 919 | unsigned int xfer_size = SCpnt->request_bufflen; |
| 894 | int good_bytes = (result == 0 ? this_count : 0); | 920 | unsigned int good_bytes = result ? 0 : xfer_size; |
| 895 | sector_t block_sectors = 1; | 921 | u64 start_lba = SCpnt->request->sector; |
| 896 | u64 first_err_block; | 922 | u64 bad_lba; |
| 897 | sector_t error_sector; | ||
| 898 | struct scsi_sense_hdr sshdr; | 923 | struct scsi_sense_hdr sshdr; |
| 899 | int sense_valid = 0; | 924 | int sense_valid = 0; |
| 900 | int sense_deferred = 0; | 925 | int sense_deferred = 0; |
| @@ -905,7 +930,6 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) | |||
| 905 | if (sense_valid) | 930 | if (sense_valid) |
| 906 | sense_deferred = scsi_sense_is_deferred(&sshdr); | 931 | sense_deferred = scsi_sense_is_deferred(&sshdr); |
| 907 | } | 932 | } |
| 908 | |||
| 909 | #ifdef CONFIG_SCSI_LOGGING | 933 | #ifdef CONFIG_SCSI_LOGGING |
| 910 | SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", | 934 | SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", |
| 911 | SCpnt->request->rq_disk->disk_name, result)); | 935 | SCpnt->request->rq_disk->disk_name, result)); |
| @@ -915,89 +939,72 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) | |||
| 915 | sshdr.sense_key, sshdr.asc, sshdr.ascq)); | 939 | sshdr.sense_key, sshdr.asc, sshdr.ascq)); |
| 916 | } | 940 | } |
| 917 | #endif | 941 | #endif |
| 918 | /* | 942 | if (driver_byte(result) != DRIVER_SENSE && |
| 919 | Handle MEDIUM ERRORs that indicate partial success. Since this is a | 943 | (!sense_valid || sense_deferred)) |
| 920 | relatively rare error condition, no care is taken to avoid | 944 | goto out; |
| 921 | unnecessary additional work such as memcpy's that could be avoided. | ||
| 922 | */ | ||
| 923 | if (driver_byte(result) != 0 && | ||
| 924 | sense_valid && !sense_deferred) { | ||
| 925 | switch (sshdr.sense_key) { | ||
| 926 | case MEDIUM_ERROR: | ||
| 927 | if (!blk_fs_request(SCpnt->request)) | ||
| 928 | break; | ||
| 929 | info_valid = scsi_get_sense_info_fld( | ||
| 930 | SCpnt->sense_buffer, SCSI_SENSE_BUFFERSIZE, | ||
| 931 | &first_err_block); | ||
| 932 | /* | ||
| 933 | * May want to warn and skip if following cast results | ||
| 934 | * in actual truncation (if sector_t < 64 bits) | ||
| 935 | */ | ||
| 936 | error_sector = (sector_t)first_err_block; | ||
| 937 | if (SCpnt->request->bio != NULL) | ||
| 938 | block_sectors = bio_sectors(SCpnt->request->bio); | ||
| 939 | switch (SCpnt->device->sector_size) { | ||
| 940 | case 1024: | ||
| 941 | error_sector <<= 1; | ||
| 942 | if (block_sectors < 2) | ||
| 943 | block_sectors = 2; | ||
| 944 | break; | ||
| 945 | case 2048: | ||
| 946 | error_sector <<= 2; | ||
| 947 | if (block_sectors < 4) | ||
| 948 | block_sectors = 4; | ||
| 949 | break; | ||
| 950 | case 4096: | ||
| 951 | error_sector <<=3; | ||
| 952 | if (block_sectors < 8) | ||
| 953 | block_sectors = 8; | ||
| 954 | break; | ||
| 955 | case 256: | ||
| 956 | error_sector >>= 1; | ||
| 957 | break; | ||
| 958 | default: | ||
| 959 | break; | ||
| 960 | } | ||
| 961 | 945 | ||
| 962 | error_sector &= ~(block_sectors - 1); | 946 | switch (sshdr.sense_key) { |
| 963 | good_bytes = (error_sector - SCpnt->request->sector) << 9; | 947 | case HARDWARE_ERROR: |
| 964 | if (good_bytes < 0 || good_bytes >= this_count) | 948 | case MEDIUM_ERROR: |
| 965 | good_bytes = 0; | 949 | if (!blk_fs_request(SCpnt->request)) |
| 950 | goto out; | ||
| 951 | info_valid = scsi_get_sense_info_fld(SCpnt->sense_buffer, | ||
| 952 | SCSI_SENSE_BUFFERSIZE, | ||
| 953 | &bad_lba); | ||
| 954 | if (!info_valid) | ||
| 955 | goto out; | ||
| 956 | if (xfer_size <= SCpnt->device->sector_size) | ||
| 957 | goto out; | ||
| 958 | switch (SCpnt->device->sector_size) { | ||
| 959 | case 256: | ||
| 960 | start_lba <<= 1; | ||
| 966 | break; | 961 | break; |
| 967 | 962 | case 512: | |
| 968 | case RECOVERED_ERROR: /* an error occurred, but it recovered */ | ||
| 969 | case NO_SENSE: /* LLDD got sense data */ | ||
| 970 | /* | ||
| 971 | * Inform the user, but make sure that it's not treated | ||
| 972 | * as a hard error. | ||
| 973 | */ | ||
| 974 | scsi_print_sense("sd", SCpnt); | ||
| 975 | SCpnt->result = 0; | ||
| 976 | memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); | ||
| 977 | good_bytes = this_count; | ||
| 978 | break; | 963 | break; |
| 979 | 964 | case 1024: | |
| 980 | case ILLEGAL_REQUEST: | 965 | start_lba >>= 1; |
| 981 | if (SCpnt->device->use_10_for_rw && | 966 | break; |
| 982 | (SCpnt->cmnd[0] == READ_10 || | 967 | case 2048: |
| 983 | SCpnt->cmnd[0] == WRITE_10)) | 968 | start_lba >>= 2; |
| 984 | SCpnt->device->use_10_for_rw = 0; | 969 | break; |
| 985 | if (SCpnt->device->use_10_for_ms && | 970 | case 4096: |
| 986 | (SCpnt->cmnd[0] == MODE_SENSE_10 || | 971 | start_lba >>= 3; |
| 987 | SCpnt->cmnd[0] == MODE_SELECT_10)) | ||
| 988 | SCpnt->device->use_10_for_ms = 0; | ||
| 989 | break; | 972 | break; |
| 990 | |||
| 991 | default: | 973 | default: |
| 974 | /* Print something here with limiting frequency. */ | ||
| 975 | goto out; | ||
| 992 | break; | 976 | break; |
| 993 | } | 977 | } |
| 978 | /* This computation should always be done in terms of | ||
| 979 | * the resolution of the device's medium. | ||
| 980 | */ | ||
| 981 | good_bytes = (bad_lba - start_lba)*SCpnt->device->sector_size; | ||
| 982 | break; | ||
| 983 | case RECOVERED_ERROR: | ||
| 984 | case NO_SENSE: | ||
| 985 | /* Inform the user, but make sure that it's not treated | ||
| 986 | * as a hard error. | ||
| 987 | */ | ||
| 988 | scsi_print_sense("sd", SCpnt); | ||
| 989 | SCpnt->result = 0; | ||
| 990 | memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); | ||
| 991 | good_bytes = xfer_size; | ||
| 992 | break; | ||
| 993 | case ILLEGAL_REQUEST: | ||
| 994 | if (SCpnt->device->use_10_for_rw && | ||
| 995 | (SCpnt->cmnd[0] == READ_10 || | ||
| 996 | SCpnt->cmnd[0] == WRITE_10)) | ||
| 997 | SCpnt->device->use_10_for_rw = 0; | ||
| 998 | if (SCpnt->device->use_10_for_ms && | ||
| 999 | (SCpnt->cmnd[0] == MODE_SENSE_10 || | ||
| 1000 | SCpnt->cmnd[0] == MODE_SELECT_10)) | ||
| 1001 | SCpnt->device->use_10_for_ms = 0; | ||
| 1002 | break; | ||
| 1003 | default: | ||
| 1004 | break; | ||
| 994 | } | 1005 | } |
| 995 | /* | 1006 | out: |
| 996 | * This calls the generic completion function, now that we know | 1007 | scsi_io_completion(SCpnt, good_bytes); |
| 997 | * how many actual sectors finished, and how many sectors we need | ||
| 998 | * to say have failed. | ||
| 999 | */ | ||
| 1000 | scsi_io_completion(SCpnt, good_bytes, block_sectors << 9); | ||
| 1001 | } | 1008 | } |
| 1002 | 1009 | ||
| 1003 | static int media_not_present(struct scsi_disk *sdkp, | 1010 | static int media_not_present(struct scsi_disk *sdkp, |
