Commit 1b26d29ccd592ea585c7cc291384184c5568da92

Authored by Paolo Bonzini
Committed by Jeff Garzik
1 parent 6ca8e79466

[libata] scsi: implement MODE SELECT command

The cache_type file in sysfs lets users configure the disk cache in
write-through or write-back modes.  However, ata disks do not support
writing to the file because they do not implement the MODE SELECT
command.

This patch adds a translation from MODE SELECT (for the caching page
only) to the ATA SET FEATURES command.  The set of changeable parameters
answered by MODE SENSE is also adjusted accordingly.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>

Showing 1 changed file with 188 additions and 6 deletions Side-by-side Diff

drivers/ata/libata-scsi.c
... ... @@ -2243,7 +2243,7 @@
2243 2243 static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable)
2244 2244 {
2245 2245 modecpy(buf, def_cache_mpage, sizeof(def_cache_mpage), changeable);
2246   - if (!changeable && ata_id_wcache_enabled(id))
  2246 + if (changeable || ata_id_wcache_enabled(id))
2247 2247 buf[2] |= (1 << 2); /* write cache enable */
2248 2248 if (!changeable && !ata_id_rahead_enabled(id))
2249 2249 buf[12] |= (1 << 5); /* disable read ahead */
... ... @@ -3107,6 +3107,188 @@
3107 3107 }
3108 3108  
3109 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 +/**
3110 3292 * ata_get_xlat_func - check if SCSI to ATA translation is possible
3111 3293 * @dev: ATA device
3112 3294 * @cmd: SCSI command opcode to consider
... ... @@ -3146,6 +3328,11 @@
3146 3328 case ATA_16:
3147 3329 return ata_scsi_pass_thru;
3148 3330  
  3331 + case MODE_SELECT:
  3332 + case MODE_SELECT_10:
  3333 + return ata_scsi_mode_select_xlat;
  3334 + break;
  3335 +
3149 3336 case START_STOP:
3150 3337 return ata_scsi_start_stop_xlat;
3151 3338 }
... ... @@ -3336,11 +3523,6 @@
3336 3523 case MODE_SENSE:
3337 3524 case MODE_SENSE_10:
3338 3525 ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense);
3339   - break;
3340   -
3341   - case MODE_SELECT: /* unconditionally return */
3342   - case MODE_SELECT_10: /* bad-field-in-cdb */
3343   - ata_scsi_invalid_field(cmd);
3344 3526 break;
3345 3527  
3346 3528 case READ_CAPACITY: