diff options
Diffstat (limited to 'drivers/ata/libata-scsi.c')
-rw-r--r-- | drivers/ata/libata-scsi.c | 255 |
1 files changed, 232 insertions, 23 deletions
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 8ec81ca8f659..e3bda074fa12 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
@@ -1655,7 +1655,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) | |||
1655 | if (unlikely(scmd->cmd_len < 10)) | 1655 | if (unlikely(scmd->cmd_len < 10)) |
1656 | goto invalid_fld; | 1656 | goto invalid_fld; |
1657 | scsi_10_lba_len(cdb, &block, &n_block); | 1657 | scsi_10_lba_len(cdb, &block, &n_block); |
1658 | if (unlikely(cdb[1] & (1 << 3))) | 1658 | if (cdb[1] & (1 << 3)) |
1659 | tf_flags |= ATA_TFLAG_FUA; | 1659 | tf_flags |= ATA_TFLAG_FUA; |
1660 | break; | 1660 | break; |
1661 | case READ_6: | 1661 | case READ_6: |
@@ -1675,7 +1675,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) | |||
1675 | if (unlikely(scmd->cmd_len < 16)) | 1675 | if (unlikely(scmd->cmd_len < 16)) |
1676 | goto invalid_fld; | 1676 | goto invalid_fld; |
1677 | scsi_16_lba_len(cdb, &block, &n_block); | 1677 | scsi_16_lba_len(cdb, &block, &n_block); |
1678 | if (unlikely(cdb[1] & (1 << 3))) | 1678 | if (cdb[1] & (1 << 3)) |
1679 | tf_flags |= ATA_TFLAG_FUA; | 1679 | tf_flags |= ATA_TFLAG_FUA; |
1680 | break; | 1680 | break; |
1681 | default: | 1681 | default: |
@@ -2205,9 +2205,33 @@ static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf) | |||
2205 | } | 2205 | } |
2206 | 2206 | ||
2207 | /** | 2207 | /** |
2208 | * modecpy - Prepare response for MODE SENSE | ||
2209 | * @dest: output buffer | ||
2210 | * @src: data being copied | ||
2211 | * @n: length of mode page | ||
2212 | * @changeable: whether changeable parameters are requested | ||
2213 | * | ||
2214 | * Generate a generic MODE SENSE page for either current or changeable | ||
2215 | * parameters. | ||
2216 | * | ||
2217 | * LOCKING: | ||
2218 | * None. | ||
2219 | */ | ||
2220 | static void modecpy(u8 *dest, const u8 *src, int n, bool changeable) | ||
2221 | { | ||
2222 | if (changeable) { | ||
2223 | memcpy(dest, src, 2); | ||
2224 | memset(dest + 2, 0, n - 2); | ||
2225 | } else { | ||
2226 | memcpy(dest, src, n); | ||
2227 | } | ||
2228 | } | ||
2229 | |||
2230 | /** | ||
2208 | * ata_msense_caching - Simulate MODE SENSE caching info page | 2231 | * ata_msense_caching - Simulate MODE SENSE caching info page |
2209 | * @id: device IDENTIFY data | 2232 | * @id: device IDENTIFY data |
2210 | * @buf: output buffer | 2233 | * @buf: output buffer |
2234 | * @changeable: whether changeable parameters are requested | ||
2211 | * | 2235 | * |
2212 | * Generate a caching info page, which conditionally indicates | 2236 | * Generate a caching info page, which conditionally indicates |
2213 | * write caching to the SCSI layer, depending on device | 2237 | * write caching to the SCSI layer, depending on device |
@@ -2216,12 +2240,12 @@ static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf) | |||
2216 | * LOCKING: | 2240 | * LOCKING: |
2217 | * None. | 2241 | * None. |
2218 | */ | 2242 | */ |
2219 | static unsigned int ata_msense_caching(u16 *id, u8 *buf) | 2243 | static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable) |
2220 | { | 2244 | { |
2221 | memcpy(buf, def_cache_mpage, sizeof(def_cache_mpage)); | 2245 | modecpy(buf, def_cache_mpage, sizeof(def_cache_mpage), changeable); |
2222 | if (ata_id_wcache_enabled(id)) | 2246 | if (changeable || ata_id_wcache_enabled(id)) |
2223 | buf[2] |= (1 << 2); /* write cache enable */ | 2247 | buf[2] |= (1 << 2); /* write cache enable */ |
2224 | if (!ata_id_rahead_enabled(id)) | 2248 | if (!changeable && !ata_id_rahead_enabled(id)) |
2225 | buf[12] |= (1 << 5); /* disable read ahead */ | 2249 | buf[12] |= (1 << 5); /* disable read ahead */ |
2226 | return sizeof(def_cache_mpage); | 2250 | return sizeof(def_cache_mpage); |
2227 | } | 2251 | } |
@@ -2229,30 +2253,33 @@ static unsigned int ata_msense_caching(u16 *id, u8 *buf) | |||
2229 | /** | 2253 | /** |
2230 | * ata_msense_ctl_mode - Simulate MODE SENSE control mode page | 2254 | * ata_msense_ctl_mode - Simulate MODE SENSE control mode page |
2231 | * @buf: output buffer | 2255 | * @buf: output buffer |
2256 | * @changeable: whether changeable parameters are requested | ||
2232 | * | 2257 | * |
2233 | * Generate a generic MODE SENSE control mode page. | 2258 | * Generate a generic MODE SENSE control mode page. |
2234 | * | 2259 | * |
2235 | * LOCKING: | 2260 | * LOCKING: |
2236 | * None. | 2261 | * None. |
2237 | */ | 2262 | */ |
2238 | static unsigned int ata_msense_ctl_mode(u8 *buf) | 2263 | static unsigned int ata_msense_ctl_mode(u8 *buf, bool changeable) |
2239 | { | 2264 | { |
2240 | memcpy(buf, def_control_mpage, sizeof(def_control_mpage)); | 2265 | modecpy(buf, def_control_mpage, sizeof(def_control_mpage), changeable); |
2241 | return sizeof(def_control_mpage); | 2266 | return sizeof(def_control_mpage); |
2242 | } | 2267 | } |
2243 | 2268 | ||
2244 | /** | 2269 | /** |
2245 | * ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page | 2270 | * ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page |
2246 | * @buf: output buffer | 2271 | * @buf: output buffer |
2272 | * @changeable: whether changeable parameters are requested | ||
2247 | * | 2273 | * |
2248 | * Generate a generic MODE SENSE r/w error recovery page. | 2274 | * Generate a generic MODE SENSE r/w error recovery page. |
2249 | * | 2275 | * |
2250 | * LOCKING: | 2276 | * LOCKING: |
2251 | * None. | 2277 | * None. |
2252 | */ | 2278 | */ |
2253 | static unsigned int ata_msense_rw_recovery(u8 *buf) | 2279 | static unsigned int ata_msense_rw_recovery(u8 *buf, bool changeable) |
2254 | { | 2280 | { |
2255 | memcpy(buf, def_rw_recovery_mpage, sizeof(def_rw_recovery_mpage)); | 2281 | modecpy(buf, def_rw_recovery_mpage, sizeof(def_rw_recovery_mpage), |
2282 | changeable); | ||
2256 | return sizeof(def_rw_recovery_mpage); | 2283 | return sizeof(def_rw_recovery_mpage); |
2257 | } | 2284 | } |
2258 | 2285 | ||
@@ -2316,11 +2343,11 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) | |||
2316 | page_control = scsicmd[2] >> 6; | 2343 | page_control = scsicmd[2] >> 6; |
2317 | switch (page_control) { | 2344 | switch (page_control) { |
2318 | case 0: /* current */ | 2345 | case 0: /* current */ |
2346 | case 1: /* changeable */ | ||
2347 | case 2: /* defaults */ | ||
2319 | break; /* supported */ | 2348 | break; /* supported */ |
2320 | case 3: /* saved */ | 2349 | case 3: /* saved */ |
2321 | goto saving_not_supp; | 2350 | goto saving_not_supp; |
2322 | case 1: /* changeable */ | ||
2323 | case 2: /* defaults */ | ||
2324 | default: | 2351 | default: |
2325 | goto invalid_fld; | 2352 | goto invalid_fld; |
2326 | } | 2353 | } |
@@ -2341,21 +2368,21 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) | |||
2341 | 2368 | ||
2342 | switch(pg) { | 2369 | switch(pg) { |
2343 | case RW_RECOVERY_MPAGE: | 2370 | case RW_RECOVERY_MPAGE: |
2344 | p += ata_msense_rw_recovery(p); | 2371 | p += ata_msense_rw_recovery(p, page_control == 1); |
2345 | break; | 2372 | break; |
2346 | 2373 | ||
2347 | case CACHE_MPAGE: | 2374 | case CACHE_MPAGE: |
2348 | p += ata_msense_caching(args->id, p); | 2375 | p += ata_msense_caching(args->id, p, page_control == 1); |
2349 | break; | 2376 | break; |
2350 | 2377 | ||
2351 | case CONTROL_MPAGE: | 2378 | case CONTROL_MPAGE: |
2352 | p += ata_msense_ctl_mode(p); | 2379 | p += ata_msense_ctl_mode(p, page_control == 1); |
2353 | break; | 2380 | break; |
2354 | 2381 | ||
2355 | case ALL_MPAGES: | 2382 | case ALL_MPAGES: |
2356 | p += ata_msense_rw_recovery(p); | 2383 | p += ata_msense_rw_recovery(p, page_control == 1); |
2357 | p += ata_msense_caching(args->id, p); | 2384 | p += ata_msense_caching(args->id, p, page_control == 1); |
2358 | p += ata_msense_ctl_mode(p); | 2385 | p += ata_msense_ctl_mode(p, page_control == 1); |
2359 | break; | 2386 | break; |
2360 | 2387 | ||
2361 | default: /* invalid page code */ | 2388 | default: /* invalid page code */ |
@@ -3080,6 +3107,188 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) | |||
3080 | } | 3107 | } |
3081 | 3108 | ||
3082 | /** | 3109 | /** |
3110 | * ata_mselect_caching - Simulate MODE SELECT for caching info page | ||
3111 | * @qc: Storage for translated ATA taskfile | ||
3112 | * @buf: input buffer | ||
3113 | * @len: number of valid bytes in the input buffer | ||
3114 | * | ||
3115 | * Prepare a taskfile to modify caching information for the device. | ||
3116 | * | ||
3117 | * LOCKING: | ||
3118 | * None. | ||
3119 | */ | ||
3120 | static int ata_mselect_caching(struct ata_queued_cmd *qc, | ||
3121 | const u8 *buf, int len) | ||
3122 | { | ||
3123 | struct ata_taskfile *tf = &qc->tf; | ||
3124 | struct ata_device *dev = qc->dev; | ||
3125 | char mpage[CACHE_MPAGE_LEN]; | ||
3126 | u8 wce; | ||
3127 | |||
3128 | /* | ||
3129 | * The first two bytes of def_cache_mpage are a header, so offsets | ||
3130 | * in mpage are off by 2 compared to buf. Same for len. | ||
3131 | */ | ||
3132 | |||
3133 | if (len != CACHE_MPAGE_LEN - 2) | ||
3134 | return -EINVAL; | ||
3135 | |||
3136 | wce = buf[0] & (1 << 2); | ||
3137 | |||
3138 | /* | ||
3139 | * Check that read-only bits are not modified. | ||
3140 | */ | ||
3141 | ata_msense_caching(dev->id, mpage, false); | ||
3142 | mpage[2] &= ~(1 << 2); | ||
3143 | mpage[2] |= wce; | ||
3144 | if (memcmp(mpage + 2, buf, CACHE_MPAGE_LEN - 2) != 0) | ||
3145 | return -EINVAL; | ||
3146 | |||
3147 | tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; | ||
3148 | tf->protocol = ATA_PROT_NODATA; | ||
3149 | tf->nsect = 0; | ||
3150 | tf->command = ATA_CMD_SET_FEATURES; | ||
3151 | tf->feature = wce ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF; | ||
3152 | return 0; | ||
3153 | } | ||
3154 | |||
3155 | /** | ||
3156 | * ata_scsiop_mode_select - Simulate MODE SELECT 6, 10 commands | ||
3157 | * @qc: Storage for translated ATA taskfile | ||
3158 | * | ||
3159 | * Converts a MODE SELECT command to an ATA SET FEATURES taskfile. | ||
3160 | * Assume this is invoked for direct access devices (e.g. disks) only. | ||
3161 | * There should be no block descriptor for other device types. | ||
3162 | * | ||
3163 | * LOCKING: | ||
3164 | * spin_lock_irqsave(host lock) | ||
3165 | */ | ||
3166 | static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc) | ||
3167 | { | ||
3168 | struct scsi_cmnd *scmd = qc->scsicmd; | ||
3169 | const u8 *cdb = scmd->cmnd; | ||
3170 | const u8 *p; | ||
3171 | u8 pg, spg; | ||
3172 | unsigned six_byte, pg_len, hdr_len, bd_len; | ||
3173 | int len; | ||
3174 | |||
3175 | VPRINTK("ENTER\n"); | ||
3176 | |||
3177 | six_byte = (cdb[0] == MODE_SELECT); | ||
3178 | if (six_byte) { | ||
3179 | if (scmd->cmd_len < 5) | ||
3180 | goto invalid_fld; | ||
3181 | |||
3182 | len = cdb[4]; | ||
3183 | hdr_len = 4; | ||
3184 | } else { | ||
3185 | if (scmd->cmd_len < 9) | ||
3186 | goto invalid_fld; | ||
3187 | |||
3188 | len = (cdb[7] << 8) + cdb[8]; | ||
3189 | hdr_len = 8; | ||
3190 | } | ||
3191 | |||
3192 | /* We only support PF=1, SP=0. */ | ||
3193 | if ((cdb[1] & 0x11) != 0x10) | ||
3194 | goto invalid_fld; | ||
3195 | |||
3196 | /* Test early for possible overrun. */ | ||
3197 | if (!scsi_sg_count(scmd) || scsi_sglist(scmd)->length < len) | ||
3198 | goto invalid_param_len; | ||
3199 | |||
3200 | p = page_address(sg_page(scsi_sglist(scmd))); | ||
3201 | |||
3202 | /* Move past header and block descriptors. */ | ||
3203 | if (len < hdr_len) | ||
3204 | goto invalid_param_len; | ||
3205 | |||
3206 | if (six_byte) | ||
3207 | bd_len = p[3]; | ||
3208 | else | ||
3209 | bd_len = (p[6] << 8) + p[7]; | ||
3210 | |||
3211 | len -= hdr_len; | ||
3212 | p += hdr_len; | ||
3213 | if (len < bd_len) | ||
3214 | goto invalid_param_len; | ||
3215 | if (bd_len != 0 && bd_len != 8) | ||
3216 | goto invalid_param; | ||
3217 | |||
3218 | len -= bd_len; | ||
3219 | p += bd_len; | ||
3220 | if (len == 0) | ||
3221 | goto skip; | ||
3222 | |||
3223 | /* Parse both possible formats for the mode page headers. */ | ||
3224 | pg = p[0] & 0x3f; | ||
3225 | if (p[0] & 0x40) { | ||
3226 | if (len < 4) | ||
3227 | goto invalid_param_len; | ||
3228 | |||
3229 | spg = p[1]; | ||
3230 | pg_len = (p[2] << 8) | p[3]; | ||
3231 | p += 4; | ||
3232 | len -= 4; | ||
3233 | } else { | ||
3234 | if (len < 2) | ||
3235 | goto invalid_param_len; | ||
3236 | |||
3237 | spg = 0; | ||
3238 | pg_len = p[1]; | ||
3239 | p += 2; | ||
3240 | len -= 2; | ||
3241 | } | ||
3242 | |||
3243 | /* | ||
3244 | * No mode subpages supported (yet) but asking for _all_ | ||
3245 | * subpages may be valid | ||
3246 | */ | ||
3247 | if (spg && (spg != ALL_SUB_MPAGES)) | ||
3248 | goto invalid_param; | ||
3249 | if (pg_len > len) | ||
3250 | goto invalid_param_len; | ||
3251 | |||
3252 | switch (pg) { | ||
3253 | case CACHE_MPAGE: | ||
3254 | if (ata_mselect_caching(qc, p, pg_len) < 0) | ||
3255 | goto invalid_param; | ||
3256 | break; | ||
3257 | |||
3258 | default: /* invalid page code */ | ||
3259 | goto invalid_param; | ||
3260 | } | ||
3261 | |||
3262 | /* | ||
3263 | * Only one page has changeable data, so we only support setting one | ||
3264 | * page at a time. | ||
3265 | */ | ||
3266 | if (len > pg_len) | ||
3267 | goto invalid_param; | ||
3268 | |||
3269 | return 0; | ||
3270 | |||
3271 | invalid_fld: | ||
3272 | /* "Invalid field in CDB" */ | ||
3273 | ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); | ||
3274 | return 1; | ||
3275 | |||
3276 | invalid_param: | ||
3277 | /* "Invalid field in parameter list" */ | ||
3278 | ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x26, 0x0); | ||
3279 | return 1; | ||
3280 | |||
3281 | invalid_param_len: | ||
3282 | /* "Parameter list length error" */ | ||
3283 | ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x1a, 0x0); | ||
3284 | return 1; | ||
3285 | |||
3286 | skip: | ||
3287 | scmd->result = SAM_STAT_GOOD; | ||
3288 | return 1; | ||
3289 | } | ||
3290 | |||
3291 | /** | ||
3083 | * ata_get_xlat_func - check if SCSI to ATA translation is possible | 3292 | * ata_get_xlat_func - check if SCSI to ATA translation is possible |
3084 | * @dev: ATA device | 3293 | * @dev: ATA device |
3085 | * @cmd: SCSI command opcode to consider | 3294 | * @cmd: SCSI command opcode to consider |
@@ -3119,6 +3328,11 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) | |||
3119 | case ATA_16: | 3328 | case ATA_16: |
3120 | return ata_scsi_pass_thru; | 3329 | return ata_scsi_pass_thru; |
3121 | 3330 | ||
3331 | case MODE_SELECT: | ||
3332 | case MODE_SELECT_10: | ||
3333 | return ata_scsi_mode_select_xlat; | ||
3334 | break; | ||
3335 | |||
3122 | case START_STOP: | 3336 | case START_STOP: |
3123 | return ata_scsi_start_stop_xlat; | 3337 | return ata_scsi_start_stop_xlat; |
3124 | } | 3338 | } |
@@ -3311,11 +3525,6 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) | |||
3311 | ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense); | 3525 | ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense); |
3312 | break; | 3526 | break; |
3313 | 3527 | ||
3314 | case MODE_SELECT: /* unconditionally return */ | ||
3315 | case MODE_SELECT_10: /* bad-field-in-cdb */ | ||
3316 | ata_scsi_invalid_field(cmd); | ||
3317 | break; | ||
3318 | |||
3319 | case READ_CAPACITY: | 3528 | case READ_CAPACITY: |
3320 | ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap); | 3529 | ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap); |
3321 | break; | 3530 | break; |