Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libata: Implement control mode page to select sense format

Implement MODE SELECT for the control mode page to allow the OS
to switch to descriptor sense.

tj: Dropped s/sb/cmd->sense_buffer/ in ata_gen_ata_sense(). Added
@dev description to ata_msense_ctl_mode().

Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Tejun Heo <tj@kernel.org>

authored by

Hannes Reinecke and committed by
Tejun Heo
06dbde5f 11093cb1

+91 -33
+2 -2
drivers/ata/libata-eh.c
··· 1679 1679 err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); 1680 1680 /* Ignore err_mask; ATA_ERR might be set */ 1681 1681 if (tf.command & ATA_SENSE) { 1682 - ata_scsi_set_sense(cmd, tf.lbah, tf.lbam, tf.lbal); 1682 + ata_scsi_set_sense(dev, cmd, tf.lbah, tf.lbam, tf.lbal); 1683 1683 qc->flags |= ATA_QCFLAG_SENSE_VALID; 1684 1684 } else { 1685 1685 ata_dev_warn(dev, "request sense failed stat %02x emask %x\n", ··· 1855 1855 sense_key = (qc->result_tf.auxiliary >> 16) & 0xff; 1856 1856 asc = (qc->result_tf.auxiliary >> 8) & 0xff; 1857 1857 ascq = qc->result_tf.auxiliary & 0xff; 1858 - ata_scsi_set_sense(qc->scsicmd, sense_key, asc, ascq); 1858 + ata_scsi_set_sense(dev, qc->scsicmd, sense_key, asc, ascq); 1859 1859 ata_scsi_set_sense_information(dev, qc->scsicmd, 1860 1860 &qc->result_tf); 1861 1861 qc->flags |= ATA_QCFLAG_SENSE_VALID;
+86 -30
drivers/ata/libata-scsi.c
··· 270 270 ata_scsi_park_show, ata_scsi_park_store); 271 271 EXPORT_SYMBOL_GPL(dev_attr_unload_heads); 272 272 273 - void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) 273 + void ata_scsi_set_sense(struct ata_device *dev, struct scsi_cmnd *cmd, 274 + u8 sk, u8 asc, u8 ascq) 274 275 { 276 + bool d_sense = (dev->flags & ATA_DFLAG_D_SENSE); 277 + 275 278 if (!cmd) 276 279 return; 277 280 278 281 cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 279 282 280 - scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq); 283 + scsi_build_sense_buffer(d_sense, cmd->sense_buffer, sk, asc, ascq); 281 284 } 282 285 283 286 void ata_scsi_set_sense_information(struct ata_device *dev, ··· 387 384 }; 388 385 EXPORT_SYMBOL_GPL(ata_common_sdev_attrs); 389 386 390 - static void ata_scsi_invalid_field(struct scsi_cmnd *cmd) 387 + static void ata_scsi_invalid_field(struct ata_device *dev, 388 + struct scsi_cmnd *cmd) 391 389 { 392 - ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0); 390 + ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x24, 0x0); 393 391 /* "Invalid field in cbd" */ 394 392 cmd->scsi_done(cmd); 395 393 } ··· 1018 1014 tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { 1019 1015 ata_to_sense_error(qc->ap->print_id, tf->command, tf->feature, 1020 1016 &sense_key, &asc, &ascq, verbose); 1021 - ata_scsi_set_sense(cmd, sense_key, asc, ascq); 1017 + ata_scsi_set_sense(qc->dev, cmd, sense_key, asc, ascq); 1022 1018 } else { 1023 1019 /* 1024 1020 * ATA PASS-THROUGH INFORMATION AVAILABLE ··· 1116 1112 tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { 1117 1113 ata_to_sense_error(qc->ap->print_id, tf->command, tf->feature, 1118 1114 &sense_key, &asc, &ascq, verbose); 1119 - ata_scsi_set_sense(cmd, sense_key, asc, ascq); 1115 + ata_scsi_set_sense(dev, cmd, sense_key, asc, ascq); 1120 1116 } else { 1121 1117 /* Could not decode error */ 1122 1118 ata_dev_warn(dev, "could not decode error status 0x%x err_mask 0x%x\n", 1123 1119 tf->command, qc->err_mask); 1124 - ata_scsi_set_sense(cmd, ABORTED_COMMAND, 0, 0); 1120 + ata_scsi_set_sense(dev, cmd, ABORTED_COMMAND, 0, 0); 1125 1121 return; 1126 1122 } 1127 1123 ··· 1444 1440 return 0; 1445 1441 1446 1442 invalid_fld: 1447 - ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); 1443 + ata_scsi_set_sense(qc->dev, scmd, ILLEGAL_REQUEST, 0x24, 0x0); 1448 1444 /* "Invalid field in cbd" */ 1449 1445 return 1; 1450 1446 skip: ··· 1683 1679 return 0; 1684 1680 1685 1681 invalid_fld: 1686 - ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); 1682 + ata_scsi_set_sense(qc->dev, scmd, ILLEGAL_REQUEST, 0x24, 0x0); 1687 1683 /* "Invalid field in cbd" */ 1688 1684 return 1; 1689 1685 1690 1686 out_of_range: 1691 - ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x21, 0x0); 1687 + ata_scsi_set_sense(qc->dev, scmd, ILLEGAL_REQUEST, 0x21, 0x0); 1692 1688 /* "Logical Block Address out of range" */ 1693 1689 return 1; 1694 1690 ··· 1785 1781 goto out_of_range; 1786 1782 /* treat all other errors as -EINVAL, fall through */ 1787 1783 invalid_fld: 1788 - ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); 1784 + ata_scsi_set_sense(qc->dev, scmd, ILLEGAL_REQUEST, 0x24, 0x0); 1789 1785 /* "Invalid field in cbd" */ 1790 1786 return 1; 1791 1787 1792 1788 out_of_range: 1793 - ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x21, 0x0); 1789 + ata_scsi_set_sense(qc->dev, scmd, ILLEGAL_REQUEST, 0x21, 0x0); 1794 1790 /* "Logical Block Address out of range" */ 1795 1791 return 1; 1796 1792 ··· 2362 2358 2363 2359 /** 2364 2360 * ata_msense_ctl_mode - Simulate MODE SENSE control mode page 2361 + * @dev: ATA device of interest 2365 2362 * @buf: output buffer 2366 2363 * @changeable: whether changeable parameters are requested 2367 2364 * ··· 2371 2366 * LOCKING: 2372 2367 * None. 2373 2368 */ 2374 - static unsigned int ata_msense_ctl_mode(u8 *buf, bool changeable) 2369 + static unsigned int ata_msense_ctl_mode(struct ata_device *dev, u8 *buf, 2370 + bool changeable) 2375 2371 { 2376 2372 modecpy(buf, def_control_mpage, sizeof(def_control_mpage), changeable); 2373 + if (changeable && (dev->flags & ATA_DFLAG_D_SENSE)) 2374 + buf[2] |= (1 << 2); /* Descriptor sense requested */ 2377 2375 return sizeof(def_control_mpage); 2378 2376 } 2379 2377 ··· 2490 2482 break; 2491 2483 2492 2484 case CONTROL_MPAGE: 2493 - p += ata_msense_ctl_mode(p, page_control == 1); 2485 + p += ata_msense_ctl_mode(args->dev, p, page_control == 1); 2494 2486 break; 2495 2487 2496 2488 case ALL_MPAGES: 2497 2489 p += ata_msense_rw_recovery(p, page_control == 1); 2498 2490 p += ata_msense_caching(args->id, p, page_control == 1); 2499 - p += ata_msense_ctl_mode(p, page_control == 1); 2491 + p += ata_msense_ctl_mode(args->dev, p, page_control == 1); 2500 2492 break; 2501 2493 2502 2494 default: /* invalid page code */ ··· 2529 2521 return 0; 2530 2522 2531 2523 invalid_fld: 2532 - ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x24, 0x0); 2524 + ata_scsi_set_sense(dev, args->cmd, ILLEGAL_REQUEST, 0x24, 0x0); 2533 2525 /* "Invalid field in cbd" */ 2534 2526 return 1; 2535 2527 2536 2528 saving_not_supp: 2537 - ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x39, 0x0); 2529 + ata_scsi_set_sense(dev, args->cmd, ILLEGAL_REQUEST, 0x39, 0x0); 2538 2530 /* "Saving parameters not supported" */ 2539 2531 return 1; 2540 2532 } ··· 3171 3163 return 0; 3172 3164 3173 3165 invalid_fld: 3174 - ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x00); 3166 + ata_scsi_set_sense(dev, scmd, ILLEGAL_REQUEST, 0x24, 0x00); 3175 3167 /* "Invalid field in cdb" */ 3176 3168 return 1; 3177 3169 } ··· 3236 3228 return 0; 3237 3229 3238 3230 invalid_fld: 3239 - ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x00); 3231 + ata_scsi_set_sense(dev, scmd, ILLEGAL_REQUEST, 0x24, 0x00); 3240 3232 /* "Invalid field in cdb" */ 3241 3233 return 1; 3242 3234 } ··· 3284 3276 tf->nsect = 0; 3285 3277 tf->command = ATA_CMD_SET_FEATURES; 3286 3278 tf->feature = wce ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF; 3279 + return 0; 3280 + } 3281 + 3282 + /** 3283 + * ata_mselect_control - Simulate MODE SELECT for control page 3284 + * @qc: Storage for translated ATA taskfile 3285 + * @buf: input buffer 3286 + * @len: number of valid bytes in the input buffer 3287 + * 3288 + * Prepare a taskfile to modify caching information for the device. 3289 + * 3290 + * LOCKING: 3291 + * None. 3292 + */ 3293 + static int ata_mselect_control(struct ata_queued_cmd *qc, 3294 + const u8 *buf, int len) 3295 + { 3296 + struct ata_device *dev = qc->dev; 3297 + char mpage[CONTROL_MPAGE_LEN]; 3298 + u8 d_sense; 3299 + 3300 + /* 3301 + * The first two bytes of def_control_mpage are a header, so offsets 3302 + * in mpage are off by 2 compared to buf. Same for len. 3303 + */ 3304 + 3305 + if (len != CONTROL_MPAGE_LEN - 2) 3306 + return -EINVAL; 3307 + 3308 + d_sense = buf[0] & (1 << 2); 3309 + 3310 + /* 3311 + * Check that read-only bits are not modified. 3312 + */ 3313 + ata_msense_ctl_mode(dev, mpage, false); 3314 + mpage[2] &= ~(1 << 2); 3315 + mpage[2] |= d_sense; 3316 + if (memcmp(mpage + 2, buf, CONTROL_MPAGE_LEN - 2) != 0) 3317 + return -EINVAL; 3318 + if (d_sense & (1 << 2)) 3319 + dev->flags |= ATA_DFLAG_D_SENSE; 3320 + else 3321 + dev->flags &= ~ATA_DFLAG_D_SENSE; 3322 + qc->scsicmd->result = SAM_STAT_GOOD; 3323 + qc->scsicmd->scsi_done(qc->scsicmd); 3287 3324 return 0; 3288 3325 } 3289 3326 ··· 3434 3381 if (ata_mselect_caching(qc, p, pg_len) < 0) 3435 3382 goto invalid_param; 3436 3383 break; 3437 - 3384 + case CONTROL_MPAGE: 3385 + if (ata_mselect_control(qc, p, pg_len) < 0) 3386 + goto invalid_param; 3387 + break; 3438 3388 default: /* invalid page code */ 3439 3389 goto invalid_param; 3440 3390 } ··· 3453 3397 3454 3398 invalid_fld: 3455 3399 /* "Invalid field in CDB" */ 3456 - ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); 3400 + ata_scsi_set_sense(qc->dev, scmd, ILLEGAL_REQUEST, 0x24, 0x0); 3457 3401 return 1; 3458 3402 3459 3403 invalid_param: 3460 3404 /* "Invalid field in parameter list" */ 3461 - ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x26, 0x0); 3405 + ata_scsi_set_sense(qc->dev, scmd, ILLEGAL_REQUEST, 0x26, 0x0); 3462 3406 return 1; 3463 3407 3464 3408 invalid_param_len: 3465 3409 /* "Parameter list length error" */ 3466 - ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x1a, 0x0); 3410 + ata_scsi_set_sense(qc->dev, scmd, ILLEGAL_REQUEST, 0x1a, 0x0); 3467 3411 return 1; 3468 3412 3469 3413 skip: ··· 3667 3611 switch(scsicmd[0]) { 3668 3612 /* TODO: worth improving? */ 3669 3613 case FORMAT_UNIT: 3670 - ata_scsi_invalid_field(cmd); 3614 + ata_scsi_invalid_field(dev, cmd); 3671 3615 break; 3672 3616 3673 3617 case INQUIRY: 3674 3618 if (scsicmd[1] & 2) /* is CmdDt set? */ 3675 - ata_scsi_invalid_field(cmd); 3619 + ata_scsi_invalid_field(dev, cmd); 3676 3620 else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */ 3677 3621 ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std); 3678 3622 else switch (scsicmd[2]) { ··· 3698 3642 ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b2); 3699 3643 break; 3700 3644 default: 3701 - ata_scsi_invalid_field(cmd); 3645 + ata_scsi_invalid_field(dev, cmd); 3702 3646 break; 3703 3647 } 3704 3648 break; ··· 3716 3660 if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16) 3717 3661 ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap); 3718 3662 else 3719 - ata_scsi_invalid_field(cmd); 3663 + ata_scsi_invalid_field(dev, cmd); 3720 3664 break; 3721 3665 3722 3666 case REPORT_LUNS: ··· 3724 3668 break; 3725 3669 3726 3670 case REQUEST_SENSE: 3727 - ata_scsi_set_sense(cmd, 0, 0, 0); 3671 + ata_scsi_set_sense(dev, cmd, 0, 0, 0); 3728 3672 cmd->result = (DRIVER_SENSE << 24); 3729 3673 cmd->scsi_done(cmd); 3730 3674 break; ··· 3748 3692 if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4])) 3749 3693 ata_scsi_rbuf_fill(&args, ata_scsiop_noop); 3750 3694 else 3751 - ata_scsi_invalid_field(cmd); 3695 + ata_scsi_invalid_field(dev, cmd); 3752 3696 break; 3753 3697 3754 3698 /* all other commands */ 3755 3699 default: 3756 - ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0); 3700 + ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x20, 0x0); 3757 3701 /* "Invalid command operation code" */ 3758 3702 cmd->scsi_done(cmd); 3759 3703 break;
+2 -1
drivers/ata/libata.h
··· 138 138 struct scsi_host_template *sht); 139 139 extern void ata_scsi_scan_host(struct ata_port *ap, int sync); 140 140 extern int ata_scsi_offline_dev(struct ata_device *dev); 141 - extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq); 141 + extern void ata_scsi_set_sense(struct ata_device *dev, 142 + struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq); 142 143 extern void ata_scsi_set_sense_information(struct ata_device *dev, 143 144 struct scsi_cmnd *cmd, 144 145 const struct ata_taskfile *tf);
+1
include/linux/libata.h
··· 180 180 ATA_DFLAG_DA = (1 << 26), /* device supports Device Attention */ 181 181 ATA_DFLAG_DEVSLP = (1 << 27), /* device supports Device Sleep */ 182 182 ATA_DFLAG_ACPI_DISABLED = (1 << 28), /* ACPI for the device is disabled */ 183 + ATA_DFLAG_D_SENSE = (1 << 29), /* Descriptor sense requested */ 183 184 184 185 ATA_DEV_UNKNOWN = 0, /* unknown device */ 185 186 ATA_DEV_ATA = 1, /* ATA device */