diff options
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r-- | drivers/scsi/sd.c | 82 |
1 files changed, 63 insertions, 19 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index bd0806e64e85..953773cb26d9 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
@@ -490,7 +490,8 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) | |||
490 | unsigned int max_blocks = 0; | 490 | unsigned int max_blocks = 0; |
491 | 491 | ||
492 | q->limits.discard_zeroes_data = sdkp->lbprz; | 492 | q->limits.discard_zeroes_data = sdkp->lbprz; |
493 | q->limits.discard_alignment = sdkp->unmap_alignment; | 493 | q->limits.discard_alignment = sdkp->unmap_alignment * |
494 | logical_block_size; | ||
494 | q->limits.discard_granularity = | 495 | q->limits.discard_granularity = |
495 | max(sdkp->physical_block_size, | 496 | max(sdkp->physical_block_size, |
496 | sdkp->unmap_granularity * logical_block_size); | 497 | sdkp->unmap_granularity * logical_block_size); |
@@ -2021,16 +2022,26 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) | |||
2021 | 2022 | ||
2022 | int dbd; | 2023 | int dbd; |
2023 | int modepage; | 2024 | int modepage; |
2025 | int first_len; | ||
2024 | struct scsi_mode_data data; | 2026 | struct scsi_mode_data data; |
2025 | struct scsi_sense_hdr sshdr; | 2027 | struct scsi_sense_hdr sshdr; |
2026 | int old_wce = sdkp->WCE; | 2028 | int old_wce = sdkp->WCE; |
2027 | int old_rcd = sdkp->RCD; | 2029 | int old_rcd = sdkp->RCD; |
2028 | int old_dpofua = sdkp->DPOFUA; | 2030 | int old_dpofua = sdkp->DPOFUA; |
2029 | 2031 | ||
2030 | if (sdp->skip_ms_page_8) | 2032 | first_len = 4; |
2031 | goto defaults; | 2033 | if (sdp->skip_ms_page_8) { |
2032 | 2034 | if (sdp->type == TYPE_RBC) | |
2033 | if (sdp->type == TYPE_RBC) { | 2035 | goto defaults; |
2036 | else { | ||
2037 | if (sdp->skip_ms_page_3f) | ||
2038 | goto defaults; | ||
2039 | modepage = 0x3F; | ||
2040 | if (sdp->use_192_bytes_for_3f) | ||
2041 | first_len = 192; | ||
2042 | dbd = 0; | ||
2043 | } | ||
2044 | } else if (sdp->type == TYPE_RBC) { | ||
2034 | modepage = 6; | 2045 | modepage = 6; |
2035 | dbd = 8; | 2046 | dbd = 8; |
2036 | } else { | 2047 | } else { |
@@ -2039,13 +2050,15 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) | |||
2039 | } | 2050 | } |
2040 | 2051 | ||
2041 | /* cautiously ask */ | 2052 | /* cautiously ask */ |
2042 | res = sd_do_mode_sense(sdp, dbd, modepage, buffer, 4, &data, &sshdr); | 2053 | res = sd_do_mode_sense(sdp, dbd, modepage, buffer, first_len, |
2054 | &data, &sshdr); | ||
2043 | 2055 | ||
2044 | if (!scsi_status_is_good(res)) | 2056 | if (!scsi_status_is_good(res)) |
2045 | goto bad_sense; | 2057 | goto bad_sense; |
2046 | 2058 | ||
2047 | if (!data.header_length) { | 2059 | if (!data.header_length) { |
2048 | modepage = 6; | 2060 | modepage = 6; |
2061 | first_len = 0; | ||
2049 | sd_printk(KERN_ERR, sdkp, "Missing header in MODE_SENSE response\n"); | 2062 | sd_printk(KERN_ERR, sdkp, "Missing header in MODE_SENSE response\n"); |
2050 | } | 2063 | } |
2051 | 2064 | ||
@@ -2058,30 +2071,61 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) | |||
2058 | */ | 2071 | */ |
2059 | if (len < 3) | 2072 | if (len < 3) |
2060 | goto bad_sense; | 2073 | goto bad_sense; |
2061 | if (len > 20) | 2074 | else if (len > SD_BUF_SIZE) { |
2062 | len = 20; | 2075 | sd_printk(KERN_NOTICE, sdkp, "Truncating mode parameter " |
2063 | 2076 | "data from %d to %d bytes\n", len, SD_BUF_SIZE); | |
2064 | /* Take headers and block descriptors into account */ | 2077 | len = SD_BUF_SIZE; |
2065 | len += data.header_length + data.block_descriptor_length; | 2078 | } |
2066 | if (len > SD_BUF_SIZE) | 2079 | if (modepage == 0x3F && sdp->use_192_bytes_for_3f) |
2067 | goto bad_sense; | 2080 | len = 192; |
2068 | 2081 | ||
2069 | /* Get the data */ | 2082 | /* Get the data */ |
2070 | res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr); | 2083 | if (len > first_len) |
2084 | res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, | ||
2085 | &data, &sshdr); | ||
2071 | 2086 | ||
2072 | if (scsi_status_is_good(res)) { | 2087 | if (scsi_status_is_good(res)) { |
2073 | int offset = data.header_length + data.block_descriptor_length; | 2088 | int offset = data.header_length + data.block_descriptor_length; |
2074 | 2089 | ||
2075 | if (offset >= SD_BUF_SIZE - 2) { | 2090 | while (offset < len) { |
2076 | sd_printk(KERN_ERR, sdkp, "Malformed MODE SENSE response\n"); | 2091 | u8 page_code = buffer[offset] & 0x3F; |
2077 | goto defaults; | 2092 | u8 spf = buffer[offset] & 0x40; |
2093 | |||
2094 | if (page_code == 8 || page_code == 6) { | ||
2095 | /* We're interested only in the first 3 bytes. | ||
2096 | */ | ||
2097 | if (len - offset <= 2) { | ||
2098 | sd_printk(KERN_ERR, sdkp, "Incomplete " | ||
2099 | "mode parameter data\n"); | ||
2100 | goto defaults; | ||
2101 | } else { | ||
2102 | modepage = page_code; | ||
2103 | goto Page_found; | ||
2104 | } | ||
2105 | } else { | ||
2106 | /* Go to the next page */ | ||
2107 | if (spf && len - offset > 3) | ||
2108 | offset += 4 + (buffer[offset+2] << 8) + | ||
2109 | buffer[offset+3]; | ||
2110 | else if (!spf && len - offset > 1) | ||
2111 | offset += 2 + buffer[offset+1]; | ||
2112 | else { | ||
2113 | sd_printk(KERN_ERR, sdkp, "Incomplete " | ||
2114 | "mode parameter data\n"); | ||
2115 | goto defaults; | ||
2116 | } | ||
2117 | } | ||
2078 | } | 2118 | } |
2079 | 2119 | ||
2080 | if ((buffer[offset] & 0x3f) != modepage) { | 2120 | if (modepage == 0x3F) { |
2121 | sd_printk(KERN_ERR, sdkp, "No Caching mode page " | ||
2122 | "present\n"); | ||
2123 | goto defaults; | ||
2124 | } else if ((buffer[offset] & 0x3f) != modepage) { | ||
2081 | sd_printk(KERN_ERR, sdkp, "Got wrong page\n"); | 2125 | sd_printk(KERN_ERR, sdkp, "Got wrong page\n"); |
2082 | goto defaults; | 2126 | goto defaults; |
2083 | } | 2127 | } |
2084 | 2128 | Page_found: | |
2085 | if (modepage == 8) { | 2129 | if (modepage == 8) { |
2086 | sdkp->WCE = ((buffer[offset + 2] & 0x04) != 0); | 2130 | sdkp->WCE = ((buffer[offset + 2] & 0x04) != 0); |
2087 | sdkp->RCD = ((buffer[offset + 2] & 0x01) != 0); | 2131 | sdkp->RCD = ((buffer[offset + 2] & 0x01) != 0); |